Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Размещение в памяти полей структур, есть ли стандарт на реализацию структур? 
:(
    Опции темы
Курсант
Дата 24.10.2014, 08:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 338
Регистрация: 21.2.2009
Где: Балашиха или Воро неж

Репутация: нет
Всего: 4



Всем доброго времени суток! У меня есть указатель void*, когда я пытаюсь читать из памяти структуру, расположенную по этому адресу, то первое поле читается нормально, второе - сдвинуто на 2 байта, третье - на 4 байта, то есть структура из памяти читается в искажённом виде.

Конкретно: занимаюсь разбором Ethernet-пакета, пакет считан из буфера приёмника в область памяти, есть указатель на область памяти void* Pointer. Сам пакет содержит в себе запрос от протокола ARP при подключении моего устройства в локальную сеть, хотя это не принципиально.
Код

Pointer: 
0xFF 0XFF 0xFF 0xFF 0xFF 0xFF     // MAC-адрес приёмника, широковещательный адрес.
0x01 0x23 0x45 0x67 0x89 0xAB    // MAC-адрес источника
0x08 0x06     // Двухбайтовый идентификатор протокола ARP (Address Resolution Protocol
0x00 0x00     // Какие-то данные пакета ARP
0x08 0x00     // Какие-то данные пакета ARP, по несчастью совпадающие с идентификатором протокола IP.
----------

Для удобства работы у меня есть структуры Ethernet_Header, MAC_Address, Protocol_ID_in_Ethernet
Код

struct MAC_Address {
        uint8_t MAC_HH;
        uint8_t MAC_HL;
        uint8_t MAC_MH;
        uint8_t MAC_ML;
        uint8_t MAC_LH;
        uint8_t MAC_LL;
};

struct  Protocol_ID_in_Ethernet {
        uint8_t H;
        uint8_t L;
};

struct Ethernet_Header {
        struct MAC_Address DstMACAddress;
        struct MAC_Address SrcMACAddress;
        struct Protocol_ID_in_Ethernet UpperProtocolID;
};

Работая с указателем на пакет как с указателем на структуру Ethernet_Header, я пытаюсь выяснить, пакет какого протокола содержится в данных пакета Ethernet. Для этого я считываю из области памяти, на которую указывает Pointer, структуры типа MAC_Address и Protocol_ID_in_Ethernet:
Код

struct MAC_Address tmpMAC1;
struct MAC_Address tmpMAC2;
struct Protocol_ID_in_Ethernet tmpID;

tmpMAC1 = ((struct Ethernet_Header*)Pointer)->DstMACAddress;
tmpMAC2 = ((struct Ethernet_Header*)Pointer)->SrcMACAddress;
tmpID =  ((struct Ethernet_Header*)Pointer)->UpperProtocolID;


После этого в переменных я получаю следующие значения
Код

tmpMAC1 == 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF // MAC-адрес назначения, принят без искажения
tmpMAC2 == 0x45 0x67 0x89 0xAB 0x08 0x06 // получено со сдвигом на 2 байта, поэтому последние 2 байта - идентификатор протокола ARP
tmpID == 0x08 0x00      // Сдвинуто на 4 байта, вместо идентификатора ARP получено это значение, являющееся идентификатором протокола IP. Программа работает не правильно.
.

Я исходил из того, что в структуре не предусмотрены пропуски в два байта между полями. Компилятор почему-то посчитал по другому. Я наверное попробую объявить переменную типа Ethernet_Header и считать туда весь заголовок, но вообще изначально я не хотел ничего считывать ни в какие переменные, а использовать в качестве переменной саму область памяти, используя Pointer в качестве указателя. Т.е. мне не хотелось бы заниматься копированием области памяти, скопированной из буфера приёмника - это уже явно избыточные операции.

Собственно вопрос: кто виноват и что делать? smile

З.Ы. Компилятор CMC-ARM (для контроллеров с ARM-архитектурой).

Это сообщение отредактировал(а) Курсант - 24.10.2014, 08:52
PM ICQ Skype   Вверх
xvr
Дата 24.10.2014, 09:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Стандарт С99, параграф 6.7.2.1 (Structure and union specifiers)
Цитата

15 There may be unnamed padding at the end of a structure or union.

так что имеет право  smile 
В С++ есть аналогичное замечание в п 9.2 абзац 21 -
Цитата

There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning,
as necessary to achieve appropriate alignment.


Попробуйте аттрибут (или прагму) packed (не знаю, как она называется у CMC-ARM)

PM MAIL   Вверх
Dem_max
Дата 24.10.2014, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



используй 
Код

#pragma pack (push, 1)
typedef struct _FIRMWARE_HEADER
{
   DWORD Ident;
   DWORD FileSize;
   DWORD FirmwareSize;
   BYTE FirmwareVerMajor;
   BYTE FirmwareVerMinor;
   BYTE FirmwareUpdate;
   BYTE FirmwareVerCommand;
   WORD FirmwareVerBootloader;
} FIRMWARE_HEADER;
#pragma pack (pop)



--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
tzirechnoy
Дата 24.10.2014, 19:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 2
Всего: 16



Я посоветую не использовать прагмапаков, а работать с char *. Поначалу -- избавит от кучи проблем с пакингом, размером полей, byte order и прочей гадостью. При этом выигрыш от описания структур как структур -- в общем невелик, намакросах можно написать почти такжэ понятно, при этом скорость редко где уменьшытся, поскольку компиляторы обычно могут сокращать константные вычисления.


PM MAIL   Вверх
Курсант
Дата 24.10.2014, 21:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 338
Регистрация: 21.2.2009
Где: Балашиха или Воро неж

Репутация: нет
Всего: 4



Спасибо всем за ответы! Прагма пак на CMC, похоже, не работает, а для отключения выравнивания полей структур есть директива __packed. У меня всё заработало, точнее, заголовок Ethernet-пакета удалось разобрать именно на те составляющие, из которых он состоит. Но дальше возникли трудности с разбором заголовка ARP-пакета, вложенного в Ethernet-пакет. А именно, структура заголовка Ethernet-пакета описывается так:

EthernetProtocol.h
Код

__packed struct MAC_Address {
        uint8_t MAC_HH;
        uint8_t MAC_HL;
        uint8_t MAC_MH;
        uint8_t MAC_ML;
        uint8_t MAC_LH;
        uint8_t MAC_LL;
};

__packed struct Protocol_ID_in_Ethernet {
        uint8_t H;
        uint8_t L;
};

__packed struct Ethernet_Header {
        struct MAC_Address DstMACAddress;
        struct MAC_Address SrcMACAddress;
        struct Protocol_ID_in_Ethernet UpperProtocolID;
};

До этого места всё работает нормально. Но как только я поправляю аналогичным образом описание заголовков ARP-пакетов:

ARPProtocol.h
Код

__packed struct IPToMACMatch {
        struct IP_Address IPAddress;
        struct MAC_Address MACAddress;
};

__packed struct ARP_Header {
        struct Protocol_ID_in_Ethernet HTYPE;  // Hardware Type
        struct Protocol_ID_in_Ethernet PTYPE;  // Protocol Type
        uint8_t HLEN;
        uint8_t PLEN;
        uint16_t OPER;
};

__packed struct ARP_Data {
         struct MAC_Address SHA;   // Source Hardware Address
         struct IP_Address SPA;    // Source Protocol Address
         struct MAC_Address THA;   // Target Hardware Address
         struct IP_Address TPA;    // Target Protocol Address
};


Начинаются проблемы. При компиляции появляется ругань на вот этот участок кода:

EthernetProtocol.h
Код

Error[C100] EthernetProtocol.h(9,28): Structure 'MAC_Address' redefinition
__packed struct MAC_Address {
        uint8_t MAC_HH;
        uint8_t MAC_HL;
        uint8_t MAC_MH;
        uint8_t MAC_ML;
        uint8_t MAC_LH;
        uint8_t MAC_LL;
};

Error[C100] EthernetProtocol.h(18,40): Structure 'Protocol_ID_in_Ethernet' redefinition
__packed struct Protocol_ID_in_Ethernet {
        uint8_t H;
        uint8_t L;
};


при этом даже если из EthernetProtocol.h убрать директивы packed, сообщения об ошибках всё равно остаются. То есть возникают проблемы, если в packed-структуре есть другие вложенные структуры. И я опять завис.

Это сообщение отредактировал(а) Курсант - 24.10.2014, 21:03
PM ICQ Skype   Вверх
tzirechnoy
Дата 24.10.2014, 22:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 2
Всего: 16



Это у Вас не вложэнные структуры, а дважды включённые файлы заголовков.
PM MAIL   Вверх
Курсант
Дата 24.10.2014, 22:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 338
Регистрация: 21.2.2009
Где: Балашиха или Воро неж

Репутация: нет
Всего: 4



Цитата(tzirechnoy @ 24.10.2014,  22:44)
Это у Вас не вложэнные структуры, а дважды включённые файлы заголовков.

Ну, в файлах заголовков у меня стоит
Код

#ifndef __ETHERNETPROTOCOL_H
#define __ETHERNETPROTOCOL_H

код

#endif

Поэтому дважды включение вроде бы исключено.
А во-вторых как-то странно получается - добавляю __packed в описание структур ARP-заголовка, и сразу появляется два включения файла заголовка. Убираю __packed из описания структур ARP-заголовка - и всё компилируется (но на уровне ARP, судя по всему, работает неправильно).
PM ICQ Skype   Вверх
tzirechnoy
Дата 25.10.2014, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 2
Всего: 16



Цитата
Ну, в файлах заголовков у меня стоит


То есть то, что у вас написано там вверху после слова "код" -- это фигня и не соответствует действительности.
В общем, я мог бы догадаться и сам, да.

Печально, но вряд ли здесь найдётся много жэлающих пытаться разбираться в секретном коде.
PM MAIL   Вверх
Курсант
Дата 25.10.2014, 13:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 338
Регистрация: 21.2.2009
Где: Балашиха или Воро неж

Репутация: нет
Всего: 4



Цитата(tzirechnoy @ 25.10.2014,  11:22)
Цитата
Ну, в файлах заголовков у меня стоит


То есть то, что у вас написано там вверху после слова "код" -- это фигня и не соответствует действительности.
В общем, я мог бы догадаться и сам, да.

Печально, но вряд ли здесь найдётся много жэлающих пытаться разбираться в секретном коде.

Мда, Вы правы, извините, но дело в том, что заголовочные файлы и си-файлы у меня достаточно объёмные, и приводить их полностью я посчитал излишним... Думаю, копаться в них нашлось бы ещё меньше желающих. Как ни странно, с ARP-заголовками работа идёт нормально даже без директив __packed. То ли компилятору одной директивы оказалось достаточно. Ну, я достаточно начинающий программист, поэтому пока займусь протоколами, а с директивами компилятора разберусь как-нибудь потом. Это работает, значит не будем ничего трогать. 

Спасибо большое за ответы.
PM ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0520 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.