Перейти к содержанию
    

Выравнивание байт

Взял за основу пример UDP обмена на плате Spartan 6. 

Используюя накопленный опыт, решил использовать струтуру в которой не нужно выравнивания (надеюсь ;-))

// структура короткого запроса
typedef struct{
	int cmd;		// код команды/запроса
	int addr;	    // адрес обращения
	int data;       // данные для записи/чтения
	unsigned int crc;
}SHORT_CMD;

Обрабатываю пакеты под отладчиком в плате.

1) Копирую нужную часть memcpy(&short_cmd, udp_packet, sizeof(SHORT_CMD));

2) Подсчитываю контрольную суссу, она сходиться

3) По коду запроса вызываю функцию обработки

call_func.thumb.png.4eb31ee62417d1802c8ecb6f1273b08f.png

В отладчике видно что поле data имеет значение 0xAA

4)Захожу в функцию

func.thumb.png.69102aeb5a6c4f394fa9f4d6dfdc3b45.png

Параметр data передается в функцию с перестановкой байт. addr, наверное тоже, но не видно так как он равен нулю.

Настройки процессора следующие:

big_endian.thumb.png.3cc054f8e5dde0850824d4af474c84d2.png

Допустим можно попутать big/little endian.

Почему компилятор корректно извлекает из структуры число, а передает его в функцию некорректно?

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Был бы Cи на линуксе, я бы сходу сказал, что структуры, передаваемые по сети нужно упаковывать с помощью директивы pragma pack, иначе компилятор все это дела выравняет сам под кеш линию и в сеть уйдет черти что, это достаточно серьезный источник проблем. Потом бы разбирался дальше.

Изменено пользователем new123

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

33 minutes ago, new123 said:

Был бы Cи на линуксе, я бы сходу сказал, что структуры, передаваемые по сети нужно упаковывать с помощью директивы pragma pack, иначе компилятор все это дела выравняет сам под кеш линию и в сеть уйдет черти что, это достаточно серьезный источник проблем. Потом бы разбирался дальше.

 

Сеть здесь ни при чем.

Создается впечатление, что отображение в отладчике и передача параметров в  функцию не одно и тоже

Такая передача не работает

 result_cmd = parser_put(short_cmd.addr, short_cmd.data);

Если объявить промежуточные переменные,то работает

int answer_addr, answer_data;

answer_addr = short_cmd.addr;
answer_data = short_cmd.data;
result_cmd = parser_put(answer_addr, answer_data);


 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On ‎5‎/‎29‎/‎2019 at 9:49 AM, misyachniy said:

Допустим можно попутать big/little endian.

Почему компилятор корректно извлекает из структуры число, а передает его в функцию некорректно?

Я так понимаю, что вы жалуетесь на parser_put(). Я вижу, что функция parser_put принимает отдельные аргументы, а на экране отладчика у вас показаны поля некой структуры rx_packet, которая непонятно какое отношение имеет к этой функции.

 

On ‎5‎/‎29‎/‎2019 at 2:09 PM, new123 said:

Был бы Cи на линуксе, я бы сходу сказал, что структуры, передаваемые по сети нужно упаковывать с помощью директивы pragma pack, иначе компилятор все это дела выравняет сам под кеш линию и в сеть уйдет черти что, это достаточно серьезный источник проблем. Потом бы разбирался дальше.

 

Во-первых язык программирования Си никак не связан с ОС Линукс, и результаты компиляции не зависят от того, применяется она или нет. Затем, pragma pack - это зло, которое делает программы непереносимыми. А в данном случае оно на структуру, состоящую из одних целых, никакого влияния не окажет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, DmitryR said:

Затем, pragma pack - это зло, которое делает программы непереносимыми

а как на переносимом коде решить вопрос выравнивания структур? Чтобы, например, в кабель, уходили как есть.

2 hours ago, DmitryR said:

А в данном случае оно на структуру, состоящую из одних целых, никакого влияния не окажет.

на разных процах с разной кеш линией окажет 100% (выровняет нулями в конце разного кол-ва). Это сейчас процы унифицировались и стали делать под одну кеш линию. Раньше было хуже с этим.

Изменено пользователем new123

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

48 minutes ago, new123 said:

а как на переносимом коде решить вопрос выравнивания структур? Чтобы, например, в кабель, уходили как есть.

на разных процах с разной кеш линией окажет 100% (выровняет нулями в конце разного кол-ва). Это сейчас процы унифицировались и стали делать под одну кеш линию. Раньше было хуже с этим.

 

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

58 minutes ago, new123 said:

а как на переносимом коде решить вопрос выравнивания структур? Чтобы, например, в кабель, уходили как есть.

никак, для каждого компилятора надо будет бороться с его собственными прагмами/атрибутами.

но можно некрасиво руками (макросы htonl / шаблоны с++) перекладывать побайтно приводя к нужной endianess.

 

Quote

 

4)Захожу в функцию

Параметр data передается в функцию с перестановкой байт.

 

ну так указано же big endian, вот константа 0x000000AA (LE) и легла в память как 0xAA000000.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

57 minutes ago, DmitryR said:

, и конечно ни один компилятор этого не делает.

я подозреваю мы о разном говорим. О каких то разных компиляторах. Вы наверное про какой то внутренний компиль Xilinx.
А так, что gcc, что intel ровняет структуры под кеш линии только в путь. Под 32, либо 64. Давно работаю с сетями, это вообще стандартная проблема, когда явно не указал, компилятор выровнял и в кабель ушли совершенно не пригодные для приема данные.

1 hour ago, DmitryR said:

до размера его линии не только бессмысленно,

ровнять имеет смысл в узких задачах. Когда очень критичен показатель промаха по кешу и важна простота работы с память в "ручном" режиме. Не зря же разрабы intel и boost создают свои аллокаторы памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/11/2019 at 1:24 PM, _pv said:

ну так указано же big endian, вот константа 0x000000AA (LE) и легла в память как 0xAA000000.

Я для проверки использую передачу 0x12345678 и по ней лучше видно как переставляются данные.

В данном случае, отладчик подавил лидирующие нули.

У меня  0xAA0000,  а не  0xAA000000.

P.S. Честно говоря не пойму при чем здесь кэш. У меня процессор 32 бита, все данные стуктуры 32 бита. 

Что нужно выравнивать?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...