Как правильно добавить 1 байт к указателю на C / C++?

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

int* a = (int*)malloc(sizeof(int));
void* b = ((char*)a)+1;   

char - 1 байт, но не определен для цели байтовой операции. Я считаю, что есть другой способ сделать это байт операции. Что за правильно способ байт операции?

PS. Я изменил пример кода, чтобы быть действительным. Теперь он скомпилирован как C++ с Clang.

6 ответов


Я думаю, вы смущены:

char - 1 байт, но не определен для цели байтовой операции. Я считаю, что есть другой способ сделать это байт операции. Что за правильно способ байт операции?

что именно вы ожидаете byte значит, если не то же самое, что char означает?

В C и в C++, chars are байт. By определение. Что такое не дело в том, что байт обязательно октетов. Байт содержит не менее 8 бит. Есть нет гарантировать, что данная платформа даже делает это возможно для ссылки на блок памяти, который составляет ровно 8 бит.


в C99, у вас есть stdint.h заголовок, который содержит int8_t и uint8_t типы, которые гарантированно будут 8 битами (и, как правило, просто typedefs для char). Помимо этого, нет реальной поддержки уровня языка для байтов в C или C++, на самом деле стандарт выходит из своего пути, чтобы сказать, что sizeof например, в единицах char (а не байт). Существует также CHAR_BIT макрос, который сообщает вам количество бит в байте, на некоторых платформах char был 9bits например. Из конечно, я предполагаю, что под байтом вы подразумеваете октет.


((char*)a)++

Это один из тех злых расширений Microsoft. Выражение приведения указателя является rvalue, но в соответствии с правилами языка C++ оператор инкремента работает только на lvalues. g++ отказывается компилировать это.


вы не должны делать этого. многие архитектуры имеют требования к выравниванию данных. Например, разыменование указателя, не выровненного по границе слова на машине SPARC, приведет к сбою программы с ошибкой шины (SIGBUS).


портативный способ разделить ваши int в байты с помощью побитовых операций (предполагая 8-битные байты):

uint8_t b3 = 0x12, b2 = 0x34, b1 = 0x56, b0 = 0x78;
uint32_t a;

a = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;

printf("%08X\r\n", a);

a = 0x89ABCDEF;

b3 = (a >> 24) & 0xFF;
b2 = (a >> 16) & 0xFF;
b1 = (a >> 8) & 0xFF;
b0 = a & 0xFF;

printf("%02X%02X%02X%02X\r\n", b3, b2, b1, b0);

то же самое можно не-переносимым достигнуто с тип каламбурно трюки с помощью unions, например:

typedef union {
    uint32_t val;
    uint8_t  bytes[4];
} DWORD_A;

typedef union {
     uint32_t val;
     struct {
         unsigned b0:8;
         unsigned b1:8;
         unsigned b2:8;
         unsigned b3:8;
     };
} DWORD_B;

однако, этот метод приводит к реализации определенного поведения и, таким образом, составляет не рекомендуется:

  • порядок байтов зависит от endianness хост-системы.
  • упаковка битовых полей не переносится.
  • добавлена сложность / накладные расходы из-за кода, генерируемого компилятором для предотвращения несоосного доступа.
  • проблемы выравнивания, по реализациям, которые не мешайте им.

((char*&)a)++;

или:

a = (int*)((char*)a+1);

надеюсь, вы точно знаете, что делаете. Во - первых, вы заканчиваете - по определению-несогласованным указателем int. В зависимости от архитектуры и ОС это может быть проблемой.


plz, используйте void*

int g = 10;
int *a = &g;
printf("a : %p\n",a);
printf("a : %p\n", ++a);
printf("a : %p\n", (void*)((char*)a+1));

a: 0xbfae35dc a : 0xbfae35e0 a: 0xbfae35e1