2011-11-09 53 views
62

Tôi đang cố gắng đọc trong một dòng ký tự, sau đó in ra số thập lục phân tương đương của các ký tự.In các ký tự thập lục phân trong C

Ví dụ, nếu tôi có một chuỗi đó là "0xc0 0xc0 abc123", nơi 2 ký tự đầu tiên là c0 trong hex và các nhân vật còn lại là abc123 trong ASCII, sau đó tôi sẽ nhận được

c0 c0 61 62 63 31 32 33 

Tuy nhiên, printf sử dụng %x cung cấp cho tôi

ffffffc0 ffffffc0 61 62 63 31 32 33 

Làm cách nào để có được kết quả mong muốn mà không có "ffffff"? Và tại sao nó chỉ c0 (và 80) có ffffff, nhưng không phải là các ký tự khác?

Trả lời

88

Bạn đang thấy ffffffchar được ký trên hệ thống của bạn. Trong C, các hàm vararg như printf sẽ quảng cáo tất cả các số nguyên nhỏ hơn int đến int. Vì char là một số nguyên (số nguyên có dấu 8 bit trong trường hợp của bạn), các ký tự của bạn đang được quảng bá tới int qua tiện ích mở rộng ký.

c080 có 1 bit hàng đầu (và âm là số nguyên 8 bit), chúng đang được gia hạn khi các mẫu khác không có trong mẫu của bạn.

char int 
c0 -> ffffffc0 
80 -> ffffff80 
61 -> 00000061 

Dưới đây là một giải pháp:

char ch = 0xC0; 
printf("%x", ch & 0xff); 

này sẽ mặt nạ ra các bit trên và giữ chỉ 8 bit thấp mà bạn muốn.

+13

Giải pháp của tôi bằng cách sử dụng một diễn viên cho 'unsigned char' là một lệnh nhỏ hơn trong gcc4.6 cho x86-64 ... – lvella

+6

Trình gỡ xuống có muốn nhận xét về câu trả lời không đúng? – Mysticial

+0

Có lẽ tôi có thể giúp.Đây là (kỹ thuật) không xác định hành vi vì specifier 'x' đòi hỏi một loại unsigned, nhưng ch được thúc đẩy để int. Mã đúng sẽ chỉ đơn giản là cast ch để unsigned, hoặc sử dụng một cast để unsigned char và specifier: 'hhx'. – 2501

2

Có thể bạn đang in từ mảng char đã ký. Hoặc in từ mảng char chưa ký hoặc mặt nạ giá trị bằng 0xff: ví dụ: ar [i] & 0xFF. Các giá trị c0 đang được mở rộng bởi vì bit (sign) cao được thiết lập.

-1

Hãy thử một cái gì đó như thế này:

int main() 
{ 
    printf("%x %x %x %x %x %x %x %x\n", 
     0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33); 
} 

nào sản xuất này:

$ ./foo 
c0 c0 61 62 63 31 32 33 
+1

@karthik vui lòng không chỉnh sửa mã của tôi để mã không còn khớp với đầu ra. – ObscureRobot

10

Bạn đang có lẽ là lưu trữ các 0xc0 giá trị trong một biến char, có lẽ là một loại ký là gì, và giá trị của bạn là tiêu cực (bộ bit quan trọng nhất). Sau đó, khi in, nó được chuyển thành int và để duy trì tính tương đương ngữ nghĩa, trình biên dịch sẽ thêm các byte bổ sung bằng 0xff, do đó, số âm int sẽ có cùng giá trị bằng số âm của bạn char. Để khắc phục điều này, chỉ cần truyền tới unsigned char khi in:

printf("%x", (unsigned char)variable); 
47

Thật vậy, có loại chuyển đổi thành int. Ngoài ra, bạn có thể buộc loại char bằng cách sử dụng% hhx specifier.

printf("%hhX", a); 
23

Bạn có thể tạo một char unsigned:

unsigned char c = 0xc5; 

In ấn nó sẽ cho C5 và không ffffffc5.

Chỉ các ký tự lớn hơn 127 được in bằng ffffff vì chúng âm (ký hiệu char).

Hoặc bạn có thể cast char khi in:

char c = 0xc5; 
printf("%x", (unsigned char)c); 
+3

+1 câu trả lời thực sự tốt nhất, nhập rõ ràng càng gần khai báo dữ liệu càng tốt (nhưng không gần hơn). –

7

Bạn có thể sử dụng hh nói printf rằng đối số là một unsigned char. Sử dụng 0 để không có đệm và 2 để đặt chiều rộng thành 2. x hoặc X cho ký tự hex thấp hơn/chữ hoa.

uint8_t a = 0x0a; 
printf("%02hhX", a); // Prints "0A" 
printf("0x%02hhx", a); // Prints "0x0a" 

Sửa: Nếu độc giả đang lo ngại về sự khẳng định năm 2501 rằng đây là bằng cách nào đó không phải là 'đúng' định dạng specifiers Tôi đề nghị họ đọc printf link một lần nữa. Cụ thể:

Mặc dù% c mong đợi đối số int, vẫn an toàn khi vượt qua char vì quảng cáo số nguyên diễn ra khi hàm variadic được gọi.

Các thông số kỹ thuật chuyển đổi chính xác cho các loại chiều rộng cố định nhân vật (int8_t, vv) được định nghĩa trong tiêu đề <cinttypes> (C++) hoặc <inttypes.h> (C) (mặc dù PRIdMAX, PRIuMAX, vv là đồng nghĩa với% jd,% ju , vv).

Đối với quan điểm của mình về chữ ký so với chưa ký, trong trường hợp này không quan trọng vì giá trị phải luôn dương và dễ dàng khớp với int đã ký. Không có ký hiệu định dạng hexideximal đã ký nào.

Chỉnh sửa 2: ("khi-to-thừa nhận-bạn-sai" edition):

Nếu bạn đọc the actual C11 standard trên trang 311 (329 file PDF), bạn tìm thấy:

hh: Chỉ định rằng sau d, i, o, u, x, hoặc X xác định chuyển đổi áp dụng cho một cuộc tranh luận signed char hoặc unsigned char (đối số sẽ được đề bạt theo trong quảng cáo teger, nhưng giá trị của nó sẽ được chuyển đổi thành signed char hoặc unsigned char trước khi in); hoặc một thông số chuyển đổi n sau đây áp dụng cho con trỏ đến đối số signed char.

+0

Thông số không chính xác cho loại uint8_t. Các kiểu chiều rộng cố định sử dụng các đặc tả in đặc biệt. Xem: 'inttypes.h' – 2501

+0

Vâng, nhưng tất cả các số nguyên varargs được ngầm đẩy mạnh vào int. – Timmmm

+0

Điều đó có thể, nhưng theo như C được xác định, hành vi là không xác định nếu bạn không sử dụng đúng specifier. – 2501

Các vấn đề liên quan