Алгоритм для записи целого числа дополнения двух в память переносимо


Скажем, у меня есть следующее:

int32 a = ...; // value of variable irrelevant; can be negative
unsigned char *buf = malloc(4); /* assuming octet bytes, this is just big 
                          enough to hold an int32 */

Существует ли эффективный и переносимый алгоритм для записи дополняющего Биг-эндианского представления a в 4-байтовый буфер buf переносимым способом? То есть, независимо от того, как машина, которую мы запускаем, представляет целые числа внутри, как я могу эффективно записать дополняющее представление этих двух a в буфер?

Это вопрос C , поэтому вы можете полагаться на стандарт C, чтобы определить, если ваш ответ соответствует требованиям переносимости.

3 2

3 ответа:

Да, вы, конечно, можете сделать это переносимо:

int32_t a = ...;
uint32_t b = a;
unsigned char *buf = malloc(sizeof a);

uint32_t mask = (1U << CHAR_BIT) - 1;  // one-byte mask

for (int i = 0; i < sizeof a; i++)
{
    int shift = CHAR_BIT * (sizeof a - i - 1); // downshift amount to put next
                                               // byte in low bits
    buf[i] = (b >> shift) & mask;  // save current byte to buffer
}

, по крайней мере, я думаю, что это правильно. Я сделаю быстрый тест.

unsigned long tmp = a; // Converts to "twos complement"
unsigned char *buf = malloc(4);
buf[0] = tmp>>24 & 255;
buf[1] = tmp>>16 & 255;
buf[2] = tmp>>8 & 255;
buf[3] = tmp & 255;

Вы можете отбросить части & 255, Если вы предполагаете CHAR_BIT == 8.

Если я правильно понимаю, вы хотите сохранить 4 байта int32 внутри буфера char, в определенном порядке(например, Нижний байт первый), независимо от того, как int32 представляется.

Давайте сначала проясним эти предположения: sizeof (char)=8, комплимент двух и sizeof(int32)=4. Нет, в вашем коде нет переносимого способа, потому что вы пытаетесь преобразовать его в char вместо unsigned char. Хранение байта в char определяется реализацией.

Но если вы храните его в unsigned char массив, есть переносимые способы. Вы можете каждый раз сдвигать значение вправо на 8 бит, чтобы сформировать байт в результирующем массиве, или с помощью побитового оператора and&:

// a is unsigned
1st byte = a & 0xFF
2nd byte = a>>8 & 0xFF
3rd byte = a>>16 & 0xFF
4th byte = a>>24 & 0xFF