2016-04-13 4 views
0

Как только вы обнаружили проблемы с выравниванием в первый раз, я не уверен, какой метод является лучшим/безопасным способом борьбы с ними. У меня есть запись, которую я собираю для передачи по потоку и наоборот, поэтому он должен соответствовать спецификации интерфейса и не содержать отступов.Ada pragma Атрибут Pack или Alignment для записей?

Учитывая пример записи:

type MyRecord is record 
a : Unsigned_8; 
b : Unsigned_32; 
end record; 

Это по умолчанию потребует 8 байт, но я могу удалить упаковку, используя 2 метода:

for MyRecord'Alignment use 1; 

или

pragma Pack (MyRecord); 

I нашли несколько вопросов, относящихся к примерам C, но не смогли найти четкого ответа на этот метод. наиболее подходящим, как определить, какой метод использовать или если они эквивалентны?

UPDATE

Когда я попытался как на мою «реальную» коду, а не простой примере я обнаружил, что атрибут выравнивания достигается то, что я искал. pragma Pack значительно уменьшил размер, но не подтвердил, но я предполагаю, что он упаковал многие перечисленные типы, которые я использую, переопределяя атрибут «Использовать размер 8» для каждого типа.

ответ

4

Для Streams вы можете оставить MyRecord без представления статей и использовать по умолчанию MyRecord’Write и MyRecord’Read; ARM 13.13.2(9) говорит

Для элементарных типов, чтение чтения (и записи операций записи) количество потоковых элементов, подразумеваемых Stream_Size для типа T; представление этих элементов потока определяется реализацией. Для составных типов атрибут Write или Read для каждого компонента вызывается в каноническом порядке, который является последним измерением, самым быстрым для массива (если соглашение о массиве не является Fortran, и в этом случае оно является первым измерением, которое отличается самым быстрым) и позиционным совокупный порядок записи.

Одним из возможных недостатков реализации GNAT (и, возможно, другие) является то, что ’Write и ’Read вызовов каждый торцевого в вызове базового программного обеспечения сети. Не проблема (за исключением возможной неэффективности), но если вы используете TCP_NODELAY (или, что еще хуже, UDP), это не поведение, которое вы ищете.

Перегрузка ’Write приводит к исходной проблеме (но, по крайней мере, она ограничивается процедурой перегрузки, поэтому остальная часть вашей программы может обрабатывать правильно выровненные данные).

Я использовал поток в памяти для этого (особенно в случае UDP); ’Write в поток в памяти, затем отправьте Stream_Element_Array в сокет.Одним из примеров является ColdFrame.Memory_Streams (.ads, .adb).

+0

+1. Упаковка должна использоваться для управления представлением в памяти, а не представлением потока. Если вам нужен конкретный формат «на проводе» (потому что другой конец ожидает такой формат), вы можете перегрузить стандартные процедуры для создания этого формата, независимо от упаковки в памяти. –

+0

Когда я делаю это, он отправляет по одному полю на пакет, а не всю сериализованную запись на пакет? – MattP

+0

См. Обновленный ответ. –

1

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

for MyRecord'Size use 40; 
for MyRecord use record 
    a at 0 range 0 .. 7; 
    b at 1 range 0 .. 31; 
end record; 

(или такой, я бы испортил некоторые из индексов здесь).

NB: редактироваться на комментарий Саймона

+1

'b на 1 ряд 0 .. 31' думаю! –

+0

Является ли предложение представления релевантным для записи в поток? (Слишком ленив, чтобы посмотреть его прямо сейчас.) –

+0

@JacobSparreAndersen: для потока я бы определил свое собственное чтение и запись, чтобы определить формат проводов, независимо от того, как компилятор упаковывает запись в память. –