Хранение целого числа без знака в структуре - PullRequest
2 голосов
/ 19 мая 2009

Я написал этот фрагмент кода, в котором я назначил целое число без знака двум различным структурам. На самом деле они одинаковы, но у одного из них есть __attribute __ ((упаковано)).


  #include 
  #include 

  struct st1{
    unsigned char opcode[3];
    unsigned int target;
  }__attribute__((packed));

  struct st2{
    unsigned char opcode[3];
    unsigned int target;
  };


  void proc(void* addr) {
    struct st1* varst1 = (struct st1*)addr;
    struct st2* varst2 = (struct st2*)addr;
    printf("opcode in varst1: %c,%c, %c\n",varst1->opcode[0],varst1->opcode[1],varst1->opcode[2]);
    printf("opcode in varst2: %c,%c,%c\n",varst2->opcode[0],varst2->opcode[1],varst2->opcode[2]);
    printf("target in varst1: %d\n",varst1->target);
    printf("target in varst2: %d\n",varst2->target);

  };

  int main(int argc,char* argv[]) {
    unsigned int* var;
    var =(unsigned int*) malloc(sizeof(unsigned int));
    *var = 0x11334433;

    proc((void*)var);

    return 0;
  }

Вывод:

opcode in varst1: 3,D,3
opcode in varst2: 3,D,3
target in varst1: 17
target in varst2: 0

Учитывая, что я храню этот номер 0x11334433 == 00010001001100110100010000110011

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

Ответы [ 3 ]

3 голосов
/ 19 мая 2009

Это связано с выравниванием данных. Большинство компиляторов будут выравнивать данные по адресным границам, что поможет с общей производительностью. Итак, в первом случае, структура с упакованным атрибутом, между char [3] и int есть дополнительный байт для выравнивания int на четырехбайтовой границе. В упакованной версии этот байт заполнения отсутствует.

byte  :      0       1         2         3      4   5   6   7
st1   : opcode[0] opcode[1] opcode[2] padding |----int------|
st2   : opcode[0] opcode[1] opcode[2] |-------int--------|

Вы выделяете целое число без знака и передаете его в функцию:

byte  :      0       1         2         3      4   5   6   7
alloc :   |-----------int------------------| |---unallocated---|
st1   : opcode[0] opcode[1] opcode[2] padding |----int------|
st2   : opcode[0] opcode[1] opcode[2] |-------int--------|

Если вы используете систему с прямым порядком байтов, то младшие восемь битов (самые правые) сохраняются в байте 0 (0x33), байт 1 имеет 0x44, байт 2 имеет 0x33, а байт 4 имеет 0x11. В структуре st1 значение int отображается в память после конца выделенного количества, а в версии st2 младший байт int отображается в байт 4, 0x11. Таким образом, st1 выдает 0, а st2 выдает 0x11.

Вам повезло, что нераспределенная память равна нулю и у вас нет проверки диапазона памяти. Запись в int в st1 и st2 в этом случае может в худшем случае повредить память, вызвать ошибки защиты памяти или ничего не делать. Он не определен и зависит от реализации менеджера памяти во время выполнения.

В общем, избегайте void *.

1 голос
/ 19 мая 2009

Ваши байты выглядят так:

00010001 00110011 01000100 00110011

Хотя, очевидно, ваша порядочность неправильна и на самом деле они такие:

00110011 01000100 00110011 00010001

Если ваша структура упакована, то первые три байта связаны с кодом операции, а четвертый является целевым, поэтому в двоичном массиве для упакованного массива задано значение 17 - 0001001.

Распакованный массив дополняется нулями, поэтому target в varst2 равен нулю.

0 голосов
/ 19 мая 2009
  • % c интерпретирует аргумент как код символа ascii и печатает символ
  • 3 0x33
  • код ascii D - 0x44
  • 17 - это 0x11

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

Цель int в распакованной версии находится за позицией int, поэтому она остается равной 0.

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