Перетворення int у 4-байтовий масив символів (C)


78

Гей, я хочу перетворити int, що вводиться користувачем, у 4 байти, які я присвоюю масиву символів. Як це можна зробити?

Приклад:

Перетворити введені користувачем значення 175 на

00000000 00000000 00000000 10101111


Проблема з усіма відповідями на сьогодні, перетворення 255 повинно призвести до того, що 0 0 0 ffце друкується як:0 0 0 ffffffff

обидва результати в 0 0 0 ffffffffзамість0 0 0 ff

Ще одним прикладом є 175, оскільки вхід друкується так, як 0, 0, 0, ffffffafколись повинен бути0, 0, 0, af


6
Як визначається ваш буфер []? Незнаковий байт зі значенням, що перевищує 127, має найбільш значущий набір бітів. Це означає від’ємне число при використанні підписаного байта. Ваш FFFFFFFF виглядає як розширена інтерпретація байта 0xFF.
Blastfurnace

Для друку ваших номерів слід використовувати формат% hhx.
Jens Gustedt

..але зверніть увагу, що %hhxце доповнення C99.
кафе

1
Nit: ви не гарантуєте, що 4 байти необхідні та достатні для зберігання int. Вам потрібні sizeof (int)байти.
pmg

Для тих, хто може зіткнутися з цим повідомленням: єдиним правильним рішенням є використання бітового зсуву на непідписаних типах, як у прийнятій відповіді. Ви можете прочитати це і зупинитися на цьому. Це і найшвидша і портативна версія. memcpyна непідписаних типах - це нормально, якщо всі типи непідписані та враховано неперевершеність. рішення для об'єднання не в порядку, вони не переносяться - навіщо писати непереносний код, коли ви можете отримати переносний код з однаковими зусиллями? Арифметичні рішення покажчиків не є нормальними, вони, можливо, повільні, безумовно, не переносні і часто викликають погано визначену поведінку.
Лундін

Відповіді:


153

Портативний спосіб зробити це (гарантуючи , що ви отримуєте 0x00 0x00 0x00 0xafвсюди) є зрушеннями використання:

Методи з використанням профспілок і memcpy()отримають різний результат на різних машинах.


Проблема, яка виникає у вас, стосується друку, а не перетворення. Я припускаю, що ви використовуєте, charа не unsigned char, і ви використовуєте такий рядок, щоб надрукувати його:

Коли будь-які типи, вужчі, ніж intпередаються printf, вони підвищуються int(або unsigned int, якщо intне можуть містити всі значення вихідного типу). Якщо charпідписано на вашій платформі, то, 0xffймовірно, не входить в діапазон цього типу, і замість нього встановлюється значення -1 (яке представлене 0xffна машині доповнення 2s).

-1 підвищується до intта має представлення 0xffffffffяк intна вашій машині, і це те, що ви бачите.

Ваше рішення полягає в тому, щоб або фактично використати unsigned char, або ж застосувати unsigned charв printfзаяві:


Відредагував моє запитання, щоб ви могли побачити проблему, яку я маю з вашим рішенням.
Jacob Nelson

2
@jacobnlsn: Проблема з способом друку, див. оновлення.
кафе

Не могли б ви пояснити "& 0xFF;" трохи, будь ласка? Що робить цей код?
ZerOne

1
ZerOne: &- побітове-AND, що дає результат, коли кожен біт дорівнює 1, якщо відповідні біти в обох операндах дорівнюють 1. a & 0xFFпотім дає результат, коли найнижчі 8 бітів однакові з найнижчими 8 бітами a, а решта бітів все нуль.
кафе

4
@rem: Незважаючи на те, що charце незвично, він має бути ширшим за 8 біт (деякі середовища програмування DSP це демонструють), тому маска просто гарантує, що в цьому випадку трапляється правильно. У звичайному випадку його все одно буде оптимізовано.
кафе

15

Ви хочете звернутися до окремих байтів 32-розрядного int? Одним з можливих методів є об'єднання:

Примітка: виправлено printf, щоб відображати непідписані значення.


Відредагував моє запитання, щоб ви могли побачити проблему, яку я маю з вашим рішенням.
Jacob Nelson

5
Я писав би uint32_t замість int, щоб не турбуватися про 32-бітові машини.
Тадеуш А. Кадлубовський

1
Будьте обережні, щоб переконатися, що ви не маєте справу з невизначеною поведінкою. stackoverflow.com/questions/11639947
bzeaman

7

У вашому питанні, ви заявили , що ви хочете , щоб перетворити введення дані користувача з 175 в 00000000 00000000 00000000 10101111, який є великими байтами порядків байт, також відомі як мережевий порядок байт .

Головним чином портативний спосіб перетворити ціле число без знака в великому Endian беззнакового масив символів, як ви запропонували з цього прикладу «175» ви дали, був би використовувати Кассіопеян htonl()функцію (яка визначається в заголовку <arpa/inet.h>на системах Linux) , щоб перетворити непідписані Int в великий порядок байтів endian, а потім використовуйте memcpy()(визначений у заголовку <string.h>для C, <cstring>для C ++), щоб скопіювати байти у ваш масив char (або без знака char).

htonl()Функція приймає беззнаковое 32-бітове ціле число в якості аргументу (на відміну від htons(), який приймає в беззнаковое 16-бітове ціле число) і перетворює його в мережевий порядок байтів від порядку хоста байт (звідси абревіатура, що приймає до мережевих Лонг, проти Host TO Network Short для htons), повертаючи результат у вигляді беззнакового 32-бітового цілого числа. Призначення цього сімейства функцій полягає у забезпеченні того, щоб усі мережеві комунікації відбувалися у великому ендіанському байтовому порядку, щоб усі машини могли спілкуватися між собою через сокет без проблем із байтовим порядком. (До речі, для тупоконечников машин, htonl(), htons(), ntohl()іntohs() функції, як правило, компілюються просто для того, щоб "не працювати", оскільки байти не потрібно перегортати, перш ніж вони будуть відправлені або отримані з сокета, оскільки вони вже в належному порядку байтів)

Ось код:

Зверніть увагу, що, як сказав caf, вам потрібно надрукувати символи як символи без підпису за допомогою %xспецифікатора формату printf .

Вищезазначений код друкується 0 0 0 afна моїй машині (машині x86_64, яка використовує мало впорядкування байтів ендіана), яка має шістнадцяткове значення для 175.


2

Ви можете спробувати:


2
Ви не повинні використовувати charдля байтів, використовуйте uint8_t. (void*)valueце просто неправильно, повинно бути &value.
Лундін

1

Навіщо потрібен проміжний привід для void * у C ++, оскільки cpp не дозволяє пряме перетворення між покажчиками, вам потрібно використовувати reinterpret_cast або casting для void *.



-1

Проблема з перетворенням (причиною того, що вона дає вам ffffff наприкінці) полягає в тому, що ваше шістнадцяткове ціле число (з яким ви використовуєте оператор & binary) інтерпретується як підписане. Перекиньте його на ціле число без знака, і все буде добре.


-1

intЕквівалентно uint32_tі charдо uint8_t.

Я покажу, як я вирішив взаємодію клієнт-сервер, надіславши фактичний час (4 байти, відформатований в епоху Unix) в 1-бітовому масиві, а потім відновив його в іншій стороні. (Примітка: протокол повинен був надіслати 1024 байти)

  • Сторона клієнта

  • Сторона сервера

Сподіваюся, це допоможе.


-2

Проблема виникає, оскільки беззнаковий символ - це 4-байтове число, а не 1-байтове, як думають багато, тому змініть його на

і відтворювати під час друку, щоб запобігти підвищенню до "int" (що C робить за замовчуванням)


-2

Ви можете просто використовувати memcpyнаступне:

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.