Chuyển một int thành mảng ký tự 4 byte (C)


78

Này, tôi đang tìm cách chuyển đổi một số nguyên được người dùng đưa vào thành 4 byte, mà tôi đang gán cho một mảng ký tự. Điều này có thể giải quyết như thế nào?

Thí dụ:

Chuyển đổi đầu vào của người dùng là 175 thành

00000000 00000000 00000000 10101111


Vấn đề với tất cả các câu trả lời cho đến nay, chuyển đổi 255 sẽ dẫn đến 0 0 0 ffmặc dù nó in ra như sau:0 0 0 ffffffff

cả hai kết quả 0 0 0 ffffffffthay vì0 0 0 ff

Một ví dụ khác là 175 khi đầu vào in ra như 0, 0, 0, ffffffafkhi nó phải là0, 0, 0, af


6
Bộ đệm của bạn [] được định nghĩa như thế nào? Một byte không dấu có giá trị lớn hơn 127 có bộ bit quan trọng nhất. Điều này biểu thị một số âm khi sử dụng một byte có dấu. FFFFFFFF của bạn trông giống như một diễn giải mở rộng dấu hiệu của byte 0xFF.
Blastfurnace,

Bạn nên sử dụng định dạng% hhx để in các số của mình.
Jens Gustedt

..nhưng lưu ý rằng đó %hhxlà một bổ sung C99.
caf

1
Nit: bạn không đảm bảo rằng 4 byte là cần thiết và đủ để giữ một int. Bạn cần sizeof (int)byte.
pmg 24/09/10

Đối với những người có thể gặp phải bài đăng này: giải pháp đúng duy nhất là sử dụng bit shift trên các loại không dấu như trong câu trả lời được chấp nhận. Bạn có thể đọc cái đó và dừng ở đó. Nó là cả hai phiên bản nhanh nhất và di động nhất. memcpyđối với các loại không có dấu là ok nếu tất cả các loại không có dấu và độ bền đã được tính đến. Các giải pháp liên minh không ổn, chúng không di động - tại sao phải viết mã không di động khi bạn có thể lấy mã di động với cùng nỗ lực? Các giải pháp số học con trỏ không ổn, chúng có thể chậm, chắc chắn là không di động và thường gọi hành vi được chỉ định kém.
Lundin

Câu trả lời:


153

Cách di động để làm điều này (đảm bảo rằng bạn có thể 0x00 0x00 0x00 0xafở khắp mọi nơi) là sử dụng ca:

Các phương pháp sử dụng kết hợp và memcpy()sẽ nhận được một kết quả khác nhau trên các máy khác nhau.


Vấn đề bạn đang gặp phải là với việc in chứ không phải là chuyển đổi. Tôi cho rằng bạn đang sử dụng charhơn là sử dụng unsigned charvà bạn đang sử dụng một dòng như thế này để in nó:

Khi bất kỳ kiểu nào hẹp hơn intđược chuyển đến printf, chúng sẽ được thăng cấp int(hoặc unsigned int, nếu intkhông thể giữ tất cả các giá trị của kiểu gốc). Nếu charđược ký trên nền tảng của bạn, thì 0xffcó khả năng không phù hợp với phạm vi của loại đó và thay vào đó, nó đang được đặt thành -1 (có đại diện 0xfftrên máy bổ sung 2s).

-1 được thăng cấp thành an int, và có đại diện 0xffffffffnhư một inttrên máy của bạn và đó là những gì bạn thấy.

Giải pháp của bạn là sử dụng thực sự hoặc sử dụng unsigned charkhác unsigned chartrong printfcâu lệnh:


Đã chỉnh sửa câu hỏi của tôi để bạn có thể thấy vấn đề tôi đang gặp phải với giải pháp của bạn.
Jacob Nelson

2
@jacobnlsn: Đó là vấn đề với cách bạn in nó, hãy xem bản cập nhật.
caf

Bạn có thể giải thích về '& 0xFF;' làm ơn một chút? Mã này làm gì?
ZerOne

1
ZerOne: &là bitwise AND, cho kết quả trong đó mỗi bit là 1, các bit tương ứng trong cả hai toán hạng là 1. a & 0xFFsau đó cho kết quả trong đó 8 bit thấp nhất giống với 8 bit thấp nhất avà các bit còn lại là tất cả bằng không.
caf

4
@rem: Mặc dù không phổ biến, charđược phép rộng hơn 8 bit (một số môi trường lập trình DSP thể hiện điều này) vì vậy mặt nạ chỉ đảm bảo điều đúng xảy ra trong trường hợp đó. Đối với trường hợp phổ biến, dù sao thì nó cũng sẽ được tối ưu hóa.
caf

15

Bạn có muốn giải quyết từng byte riêng lẻ của một int 32 bit không? Một phương pháp khả thi là kết hợp:

Lưu ý: đã sửa printf để phản ánh các giá trị chưa được đánh dấu.


Đã chỉnh sửa câu hỏi của tôi để bạn có thể thấy vấn đề tôi đang gặp phải với giải pháp của bạn.
Jacob Nelson,

5
Tôi sẽ viết uint32_t thay vì int chỉ để không lo lắng về máy 32 so với 64 bit.
Tadeusz A. Kadłubowski

1
Hãy cẩn thận để đảm bảo rằng bạn không phải đối phó với hành vi không xác định. stackoverflow.com/questions/11639947
bzeaman

7

Trong câu hỏi của mình, bạn đã nói rằng bạn muốn chuyển đổi đầu vào của người dùng là 175 thành 00000000 00000000 00000000 10101111, thứ tự byte cuối lớn , còn được gọi là thứ tự byte mạng .

Một cách chủ yếu di động để chuyển đổi số nguyên không dấu của bạn thành một mảng ký tự không dấu endian lớn, như bạn đã đề xuất từ ​​ví dụ "175" mà bạn đã đưa ra, sẽ là sử dụng htonl()hàm của C (được định nghĩa trong tiêu đề <arpa/inet.h>trên hệ thống Linux) để chuyển đổi số nguyên không dấu của bạn thành thứ tự byte cuối lớn, sau đó sử dụng memcpy()(được định nghĩa trong tiêu đề <string.h>cho C, <cstring>cho C ++) để sao chép các byte vào mảng char (hoặc char không dấu) của bạn.

Các htonl()chức năng có trong một số nguyên 32-bit unsigned như một cuộc tranh cãi (trái ngược với htons(), trong đó có một số nguyên 16-bit unsigned) và chuyển đổi nó vào mạng thứ tự byte từ thứ tự chủ byte (do đó từ viết tắt, Host ĐẾN Mạng Long, so với Host TO Network Viết tắt của htons), trả về kết quả là một số nguyên 32 bit không dấu. Mục đích của nhóm chức năng này là đảm bảo rằng tất cả các giao tiếp mạng xảy ra theo thứ tự byte cuối lớn, để tất cả các máy có thể giao tiếp với nhau qua một socket mà không gặp vấn đề về thứ tự byte. (Là một sang một bên, cho máy lớn về cuối nhỏ, các htonl(), htons(), ntohl()ntohs() các hàm thường được biên dịch để chỉ là 'no op', bởi vì các byte không cần phải được lật lại trước khi chúng được gửi hoặc nhận từ một socket vì chúng đã có thứ tự byte thích hợp)

Đây là mã:

Lưu ý rằng, như caf đã nói, bạn phải in các ký tự dưới dạng tự không dấu bằng cách sử dụng bộ %xđịnh dạng của printf .

Mã trên in 0 0 0 aftrên máy của tôi (máy x86_64, sử dụng thứ tự byte cuối ít), là hex cho 175.


2

Bạn co thể thử:


2
Bạn không nên sử dụng charcho byte, hãy sử dụng uint8_t. (void*)valuelà sai rõ ràng, nên được &value.
Lundin

1

Tại sao bạn cần truyền trung gian thành void * trong C ++ Vì cpp không cho phép chuyển đổi trực tiếp giữa các con trỏ, bạn cần sử dụng reinterpret_cast hoặc ép kiểu để void * thực hiện điều đó.


0

3
Tại sao bạn cần truyền trung gian void *trong C ++?
AnT

-1

Vấn đề với việc chuyển đổi (lý do nó mang lại cho bạn một ffffff ở cuối) là vì số nguyên hex của bạn (mà bạn đang sử dụng toán tử & nhị phân với) được hiểu là đã được ký. Truyền nó tới một số nguyên không dấu và bạn sẽ ổn.


-1

An inttương đương với uint32_tcharvới uint8_t.

Tôi sẽ trình bày cách tôi giải quyết giao tiếp máy khách-máy chủ, gửi thời gian thực (4 byte, được định dạng trong Unix epoch) trong mảng 1 bit, sau đó xây dựng lại nó ở phía bên kia. (Lưu ý: giao thức được gửi 1024 byte)

  • Phía khách hàng

  • Phía máy chủ

Hy vọng nó giúp.


-2

Vấn đề đang phát sinh vì ký tự không dấu là số 4 byte không phải số 1 byte như nhiều người nghĩ, vì vậy hãy thay đổi nó thành

và truyền trong khi in, để ngăn việc quảng bá thành 'int' (theo mặc định của C)


-2

Bạn chỉ cần sử dụng memcpynhư sau:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.