Форум программистов, компьютерный форум, киберфорум
Наши страницы
netBool
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Преобразование структуры в массив байт

Запись от netBool размещена 06.04.2018 в 16:38

Уже полтора дня потерял в поисках ответа, почему не работает вот этот код:
C++
1
2
3
      BYTE arr[6];
      BYTE* _arr = arr;
      *((jmp_far*)_arr) = jump;
где jump - это jmp_far, а BYTE - unsigned char

C++
1
2
3
4
5
6
struct jmp_far
{
  BYTE instr_push;  //здесь будет код инструкции push
  DWORD arg;         //аргумент push
  BYTE  instr_ret;    //здесь будет код инструкции ret
};
Изначально jump заполнен данными, которые хорошо видны в отладчике, но после присвоения указателя разыменнованному указателю на массив байт, все рушится. Фактически передается только 1й байт (среда VS2010)

Оказывается, есть такая маленькая настроечка:
Проект->Свойства->Свойства конфигурации->C++->Создание кода->Выравнивание членов структур->1 байт (\Zp1).
И все, вуаля! Все заработало!!
но блин, ребята, полтора дня!

До этого стояло "по умолчанию"... так вот по умолчанию, видимо, 4 байта...

PS: как верно подметил в комментариях Rius, что можно было это сделать и с помощью #pragma (работает для MinGW и GCC). Под QTCreator (где нет настроек с \Zp1) я сделал так:
C++
1
2
3
4
5
6
#pragma pack(1)
struct jmp_far
{
     //поля
};
#pragma pack()
PPS: На linux.org встретил мнение, что выравнивание по 1 байту увеличивает время доступа к полям структуры. Не проверял, в моем случае скорость не имела сильного значения.

Но можно, конечно, и без выравнивания сделать.
Думаю, на нашем примере будет наиболее оптимально так:
C++
1
2
3
4
    BYTE ch[6];
    *ch = jump.instr_push;        
    *(DWORD*)(ch+1) = jump.arg;
    *(ch+5)=jump.instr_ret;
Размещено в C++
Просмотров 665 Комментарии 9
Всего комментариев 9
Комментарии
  1. Старый комментарий
    Аватар для Rius
    Цитата:
    но блин, ребята, полтора дня!
    Лучше 5 часов потратить, потом за 5 минут долететь!
    Там ещё есть директивы, влияющие на конкретную указанную структуру, а не на весь проект.
    Вроде так выглядит:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #pragma pack(push)  /* сохранить текущие настройки выравнивания (или упаковки?) */
    #pragma pack(1)     /* установить выравнивание в 1 байт */
     
    struct jmp_far
    {
      BYTE instr_push;  //здесь будет код инструкции push
      DWORD arg;         //аргумент push
      BYTE  instr_ret;    //здесь будет код инструкции ret
    };
     
    #pragma pack(pop)   /* вернуть предыдущие настройки */
    Настройки проекта вы можете легко забыть и потерять, если скопируете код в другой проект.
    А вот в коде директивы останутся.
    Запись от Rius размещена 06.04.2018 в 17:47 Rius вне форума
    Обновил(-а) Rius 06.04.2018 в 17:49
  2. Старый комментарий
    Аватар для Avazart
    Ну или можно упаковывать структуру в байты отдельной ф-цией так как это Вам надо (почленно)
    и распаковывать так же.
    Запись от Avazart размещена 06.04.2018 в 17:53 Avazart вне форума
  3. Старый комментарий
    Аватар для netBool
    Цитата:
    Сообщение от Rius Просмотреть комментарий
    Лучше 5 часов потратить, потом за 5 минут долететь!
    Там ещё есть директивы, влияющие на конкретную указанную структуру, а не на весь проект.
    Вроде так выглядит:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #pragma pack(push)  /* сохранить текущие настройки выравнивания (или упаковки?) */
    #pragma pack(1)     /* установить выравнивание в 1 байт */
     
    struct jmp_far
    {
      BYTE instr_push;  //здесь будет код инструкции push
      DWORD arg;         //аргумент push
      BYTE  instr_ret;    //здесь будет код инструкции ret
    };
     
    #pragma pack(pop)   /* вернуть предыдущие настройки */
    Настройки проекта вы можете легко забыть и потерять, если скопируете код в другой проект.
    А вот в коде директивы останутся.
    Как раз хотел добавить, что в QTCreator под MinGW не нашел таких настроек и вышел из ситуации с помощью pragm, но вы меня опередили))
    Запись от netBool размещена 07.04.2018 в 11:28 netBool вне форума
  4. Старый комментарий
    Аватар для _SayHello
    В GCC можно объявлять структуру с атрибутом
    C
    1
    
    __attribute__((packed))
    эффект такой же вроде
    Запись от _SayHello размещена 23.04.2018 в 12:34 _SayHello вне форума
  5. Старый комментарий
    Аватар для netBool
    Кстати, если нужно копировать структуру в середину массива, то можно воспользоваться конструкцией:
    C++
    1
    2
    3
    
        BYTE* bytes = new BYTE[14];
        bytes = old;
        *((jmp_far*)(bytes+7)) = jmpToOrigin;
    где jmp_far - тип объекта jmpToOrigin
    Запись от netBool размещена 04.05.2018 в 09:59 netBool вне форума
  6. Старый комментарий
    Аватар для netBool

    Не по теме:


    Нашел еще на стеке, а потом и тут наткнулся на решение для GCC/MinGW в виде ключа компиляции -mno-ms-bitfields
    Вроде тоже на упаковку влияет. Пока не проверял

    C++ (Qt)
    1
    
    QMAKE_CXXFLAGS += -mno-ms-bitfields

    Запись от netBool размещена 11.06.2018 в 12:00 netBool вне форума
  7. Старый комментарий
    Аватар для Rius
    Цитата:
    Кстати, если нужно копировать структуру в середину массива, то можно воспользоваться конструкцией:
    Я так на ARM7TDMI сделал как-то раз. Всё же здесь просто и очевидно. А потом искал причину бага на ровном месте: число в один массив нормально копируется, а в другой такой же - хрень получается.
    Оказалось, требовалось выравнивание по границе 4 байт (32-битное слово).

    Так что вы поосторожнее с таким.

    О выравнивании памяти на ARM процессорах на простом примере.
    Запись от Rius размещена 11.06.2018 в 12:11 Rius вне форума
    Обновил(-а) Rius 11.06.2018 в 12:18
  8. Старый комментарий
    Аватар для netBool
    Цитата:
    Оказалось, требовалось выравнивание по границе 4 байт (32-битное слово).
    Любопытно. Спасибо

    Видимо, это особенность самого Си-компилятора под ARM, а не процессора ARM. Ведь memcpy сработало
    Запись от netBool размещена 11.06.2018 в 12:51 netBool вне форума
  9. Старый комментарий
    Аватар для Rius
    Сработало, да. Но причина и аппаратная в том числе.
    The curious case of unaligned access on ARM
    Запись от Rius размещена 11.06.2018 в 16:47 Rius вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru