Вопрос

Я переносирую приложение на платформу ARM в C, приложение также работает на процессоре x86 и должно быть обратно совместимым.

Теперь у меня есть некоторые проблемы с переменной выравниванием. Я прочитал руководство по GCC для__attribute__((aligned(4),packed)) Я интерпретирую то, что говорится, поскольку начало структуры выровнен с 4 байтом, и внутренняя часть остается нетронутой из -за упакованного заявления.

Первоначально у меня было это, но иногда он ставится без выровнений с границей 4 байта.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

Так что я меняю на это.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((aligned(4),packed)) CHALLENGE;

Понимание, которое я заявил ранее, кажется неверным, так как оба структуры теперь выровнены по границе 4 байта, и внутренние данные теперь выровнены по границе с четырьмя байтами, но из -за эндсианты размер структуры увеличился в размер от 42 до 44 байтов. Этот размер имеет решающее значение, поскольку у нас есть другие приложения, которые зависят от 42 байта.

Может некоторые описать мне, как выполнить операцию, которая мне нужна. Буду признателен за любую оказанную помощь.

Это было полезно?

Решение

Если вы зависите от sizeof(yourstruct) Будучи 42 байтами, вы собираетесь укусить мир не портативных предположений. Вы не сказали, для чего это предназначено, но кажется вероятным, что эндоуность содержимого структуры также имеет значение, так что у вас также может быть несоответствие с x86.

В этой ситуации я думаю, что единственный уверенный способ справиться-это использовать unsigned char[42] в тех частях, где это имеет значение. Начните с написания точной спецификации того, какие поля находятся, где в этом 42-байтовом блоке и каком Endian, затем используйте это определение, чтобы написать какой-то код для перевода между этим и структурой, с которой вы можете взаимодействовать. Код, скорее всего, будет либо код сериализации All-at-conce (он же Marshalling), либо кучкой Getters и Setters.

Другие советы

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

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

Я полагаю, у вас есть что -то вроде:

read(fd, &obj, sizeof obj)

Поскольку вы не хотите читать эти 2 байта, которые принадлежат различным данным, вы должны явно указать размер:

read(fd, &obj, 42)

Который вы можете сохранить:

typedef struct {
  //...
  enum { read_size = 42 };
} __attribute__((aligned(4),packed)) CHALLENGE;

// ...

read(fd, &obj, obj.read_size)

Или, если вы не можете использовать некоторые функции C ++ в вашем C:

typedef struct {
  //...
} __attribute__((aligned(4),packed)) CHALLENGE;
enum { CHALLENGE_read_size = 42 };

// ...

read(fd, &obj, CHALLENGE_read_size)

При следующей возможности рефакторинга я настоятельно рекомендую вам начать читать каждого члена индивидуально, что может быть легко заключено в функцию.

Какова ваша истинная цель?

Если дело в том, чтобы справиться с данными, которые находятся в файле или в проводе в определенном формате, то, что вам следует сделать, это написать некоторые процедуры маршалирования/сериализации, которые перемещают данные между структурой компилятора, которые представляют, как вы хотите справиться с данными внутри Программа и массив Char, который касается того, как данные смотрят на провод/файл.

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

Я перемещал структуры взад и вперед из Linux, Windows, Mac, C, Swift, сборки и т. Д.

Проблема не в том, что это не может быть сделано, проблема в том, что вы не можете быть ленивым и должны понимать свои инструменты.

Я не понимаю, почему ты не можешь использовать:

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

Ты Можно Используйте его, и это не требует какого -либо специального или умного кода. Я пишу много кода, который общается с рукой. Структуры - это то, что заставляет вещи работать. __attribute__ ((packed)) мой друг.

Шансы на «мир боли» - это нулевые, если вы понимаете, что происходит с обоими.

Наконец, я не могу в жизни разобрать, как вы получаете 42 или 44. INT - это 4 наших 8 байтов (в зависимости от компилятора). Это ставит число на 16+16+2 = 34 или 32+16+2 = 50 - при условии, что оно действительно упаковано.

Как я уже сказал, знание ваших инструментов является частью вашей проблемы.

Я предполагаю, что проблема в том, что 42 не делится на 4, и поэтому они выходят из выравнивания, если вы поставите несколько из этих структур назад к спине (например, распределяют память для нескольких из них, определяя размер с sizeof) Наличие размера 44 заставляет выравнивание в этих случаях, как вы просили. Однако, если внутреннее смещение каждого элемента структуры остается прежним, вы можете обработать структуру 44 байта, как если бы это было 42 байта (если вы позаботитесь о том, чтобы выровнять любые следующие данные на правильной границе).

Один трюк, чтобы попробовать, может быть оба Из этих структур внутри одного типа союза и используйте только 42-байтовую версию из каждого такого союза.

Когда я использую Linux, я обнаружил, что по echo 3 > /proc/cpu/alignment Это выпустит меня с предупреждением и решит проблему выравнивания. Это работа вокруг, но она очень полезна для определения местоположения, где структуры не могут быть смещены.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top