Jump to content

    

Recommended Posts

Взял за основу пример 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.

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

 

 

Share this post


Link to post
Share on other sites

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

Edited by new123

Share this post


Link to post
Share on other sites
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);


 

 

 

Share this post


Link to post
Share on other sites
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 - это зло, которое делает программы непереносимыми. А в данном случае оно на структуру, состоящую из одних целых, никакого влияния не окажет.

Share this post


Link to post
Share on other sites
2 hours ago, DmitryR said:

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

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

2 hours ago, DmitryR said:

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

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

Edited by new123

Share this post


Link to post
Share on other sites
48 minutes ago, new123 said:

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

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

 

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

 

 

Share this post


Link to post
Share on other sites
58 minutes ago, new123 said:

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

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

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

 

Quote

 

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

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

 

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

Share this post


Link to post
Share on other sites
57 minutes ago, DmitryR said:

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

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

1 hour ago, DmitryR said:

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

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

Share this post


Link to post
Share on other sites
On 6/11/2019 at 1:24 PM, _pv said:

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

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

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

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

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

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

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this