Как правильно добавить 1 байт к указателю в C / C ++? - PullRequest
6 голосов
/ 06 февраля 2011

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

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

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

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

Ответы [ 6 ]

4 голосов
/ 06 февраля 2011

Я думаю, вы в замешательстве:

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

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

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

4 голосов
/ 06 февраля 2011

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

2 голосов
/ 06 февраля 2011

Вы не должны этого делать. Многие архитектуры предъявляют требования к выравниванию данных. Например, разыменование указателя, не выровненного по границе слова на машине 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);

То же самое может быть не переносимым , достигаемым с помощью типа пробивания трюков через union с, таких как:

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;

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

  • Порядок байтов зависит от порядкового номера хоста.
  • Упаковка битовых полей не переносима.
  • Добавлена ​​сложность / накладные расходы из-за кода, сгенерированного компилятором для предотвращения неправильного доступа.
  • Проблемы с выравниванием в реализациях, которые не мешают им.
2 голосов
/ 06 февраля 2011

((char*)a)++

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

1 голос
/ 06 февраля 2011
((char*&)a)++;

Или:

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

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

0 голосов
/ 23 марта 2016

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...