LINUX.ORG.RU

sizeof выдает неверный размер


0

0

Есть некоторая структура, указателей не содержит. sizeof для этой структуры выдает, ну скажем, 32 байта, хотя реальный размер структуры меньше. Знаю, что в МС вижал Си есть такая штука как выравнивание, и когда этому выравниванию говоришь byte, то sizeof на мою структуру выдает верный размер. Что нужно сказать gcc (какую опцию включить или выключить), чтобы sizeof на структуру выдавал корректный размер? В мане на gcc куча всяких алигнментов, какой нужен в моем случае, я так и не понял. Помогите плиз.

anonymous

sizeof всегда выдаёт верный размер. выравнивание это не стой песни. если ты хоч им воспользоватся то сначала хорошо подумай нужно ли оно тебе. В 999 из 1000 компилер лучше тебя знает что делает.

cvv ★★★★★
()
Ответ на: комментарий от Selecter

typedef struct{ char pre[2]; // 2 unsigned int src_addr; // 4 unsigned int trg_addr; // 4 unsigned int id; // 4 char pwd[4]; // 4 unsigned char num; // 1 unsigned char cmd; // 1 unsigned char res; // 1 unsigned short d_addr; // 2 unsigned short len; // 2 unsigned short crc; // 2 // total 27 bytes }_my_data;

вот на эту структуру sizeof говорит 32 байта

anonymous
()
Ответ на: комментарий от anonymous

typedef struct{
char pre[2]; // 2
unsigned int src_addr; // 4
unsigned int trg_addr; // 4
unsigned int usr_id; // 4
char pwd[4]; // 4
unsigned char pck_num; // 1
unsigned char cmd_code; // 1
unsigned char res_code; // 1
unsigned short data_addr; // 2
unsigned short len; // 2
unsigned short crc; // 2
// total 27
}_pck_short;

//поправил с переносами

anonymous
()
Ответ на: комментарий от anonymous

>вот на эту структуру sizeof говорит 32 байта

ну и правильно делает. или тебе 5 байт жалко?? На них свет клином сошёлся??? или зачем они тебе нужны??

cvv ★★★★★
()
Ответ на: комментарий от cvv

вот хочу я отправить эти данные в сокет write'ом:
write(sd, &data, sizeof(_pck_short))
и все, в сокет кроме данных валится еще ненужный хлам
приходтся упаковывать данные из структуры в массив char и только потом отправлять массив. выравнивание здесь помогло бы.
НО
http://www.opennet.ru/openforum/vsluhforumID9/4714.html
вощем не все так просто.
всем спасибо.

anonymous
()
Ответ на: комментарий от anonymous

Компилер прав что попытался выравнить размер. Но если тебе всеже так
хочется именно 27 байтов, то надо писать так:

struct a {
char pre[2]; // 2
unsigned int src_addr; // 4
unsigned int trg_addr; // 4
unsigned int usr_id; // 4
char pwd[4]; // 4
unsigned char pck_num; // 1
unsigned char cmd_code; // 1
unsigned char res_code; // 1
unsigned short data_addr; // 2
unsigned short len; // 2
unsigned short crc; // 2
// total 27
}__attribute__ ((packed)) _pck_short;

aton
()

Я думаю, что надо примерно так:

struct foo {
     int x;
     char a, b, c, d;
} __attribute__((packed));

Я обычно для таких целей делаю так:

#define GCC_PACKED __attribute__((packed))

struct foo {
        ....
} GCC_PACKED;

:)

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

RomanU
()
Ответ на: комментарий от RomanU

RomanU :

> нужно это, например, если читаешь такую структурку из структурированного файла. Там без упаковки прочтёшь не то, что надо...

Я уже выступал по этому поводу, и остаюсь при своем мнении. В 99 случаях из 100, чтение в упакованную структуру не оправданно.

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

Die-Hard ★★★★★
()
Ответ на: комментарий от anonymous

ну в твоём случае ты идёш по правильному пути только очень неудачно поставил вопрос.

оптимальное решение тебе выше уже подсказали.

cvv ★★★★★
()
Ответ на: комментарий от Die-Hard

вообще, мне нравится решение, которое предложил RomanU Die-Hard, согласись, что работа с упакованными структурами куда элегантнее выглядит в коде, да и такая функция будет работать побыстрее, т.к. не тратися время на перекладывания данных из буфера в структуру и обратно. Но исходя из соображения партируемостии и чтобы избежать возможных проблем в будущем буду использовать неструктурированный буфер. вот что мне еще написали в другом форуме ========= и не забывайте о следующем между членами структуры(класса) могут быть промежутки в целях выравнивания структура(класс) может иметь скрытые поля ======== Мне важна надежность и портируемость, в моем случае можно пренебречь расходами времени на перекладывание данных. Так что, Die-Hard, согласен с тобой на все сто, буду использовать твой вариант.

anonymous
()
Ответ на: комментарий от anonymous

Морду тебе убить за то, что структуру в сокет шлёшь. Сериализуй всё, не ленись.

anonymous
()
Ответ на: комментарий от RomanU

Побайтово структурку из файла читать надо, ламер!

anonymous
()
Ответ на: комментарий от anonymous

anonymous (*) (25.10.2005 15:02:13):

> ...да и такая функция будет работать побыстрее, т.к. не тратися время на перекладывания данных из буфера в структуру и обратно.

В большинстве случаев оно будет _медленнее_, так ка доступ к упакованной структуре существенно медленнее, а "перекинуть" данные нужно только один раз.

Почитай выше по ссылке, только что это обсуждали.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

Исключение составляет сетевой обмен, где сервер и клиент скомпилированы по разному (разными компиляторами, с разными ключами компиляции и т.д.)

BottleHunter
()
Ответ на: комментарий от anonymous

>Исчо адин баран! НЕЛЬЗЯ ТАК ДЕЛАТЬ! ЗАПРЕЩЕНО!

Опять 25. Идиоты наступают. По-моему баран это ты, уже кучу доказательств привели, где люди, очевидно, поумнее тебя, запросто пишут структуры в файлы/сокеты. А если у тебя не хватает той части мозга, без которой ты не можешь использовать структуры - это лично твои проблемы, не других.

logIN
()
Ответ на: комментарий от logIN

logIN, ты некомпетентен, что доказываешь еще один раз. Я бы рекомендовал уже начинать разгон в сторону Великой Китайской Стены.

Zulu ★★☆☆
()
Ответ на: комментарий от Zulu

>logIN, ты некомпетентен, что доказываешь еще один раз.

Некомпетентен ты. У тебя, как и у других, нету никаких аргументов, кроме как "нет нет нет! не пишите бинари дата". Это "нет нет нет", тебе говорили для того, чтобы ты себе "ногу не прострелил", расчитывая на твою дурную голову.

Local (unix) sockets, ты не знаешь, да? Да там только структуры и гоняют! А с умом (как это сделано в иксах), можно эти структуры хоть через окены посылать.

Теоретики хреновы, вы кроме как языком трепать не способны. Я даже не говорю о том, чтобы что-то написать, а _посмотреть_ как делают другие, на практике, люди умные, стреляющие себе в ноги:

http://cvs.freedesktop.org/xorg/xc/programs/Xserver/xfixes/xfixes.c?rev=1.7&a... , смотреть в сторону
WriteToClient(client, sizeof(xXFixesQueryVersionReply), (char *)&rep);

http://cvs.freedesktop.org/xorg/xc/programs/xfs/os/io.c?view=markup тело WriteToClient.

http://cvs.freedesktop.org/xorg/xc/programs/xfs/os/connection.c?view=markup - доступ.


Про ELF, TCP/IP я уже говорил - там опять структуры, и опять в файлах/сокетах. Все шлют эти самые бинари данные и ничего. Все всё запросто переносят на любые платформы, компилируют как надо.

Надеюсь сейчас тебе стало очень стыдно. Поэтому... иди поплачь.

logIN
()
Ответ на: комментарий от Zulu

> Блин, не посылайте в сокеты binary-данные! Не посылайте! Блин, блин... нет слов...

Cам то понял что сморозил?! Данные по своей природе двоичные

aton
()
Ответ на: комментарий от aton

Гениально. Супер. "данные по природе своей двоичны".

Zulu ★★☆☆
()
Ответ на: комментарий от logIN

unix-сокеты -- это приемлимо, т.к. клиент и сервер одной архитектуры (имеется в виду byte order).
tcp и elf -- это приемлимо, так как там нет выбора. Вообще на таком низком уровне это норма.

А вот для прикладной программы это неприемлимо. Кроме случая, когда это программа "для себя", тюею никогда не будет взаимодействовать ни с чем, кроме тобой же написаным демоном с той стороны.

Zulu ★★☆☆
()
Ответ на: комментарий от Zulu

>А вот для прикладной программы это неприемлимо.

Странные люди. Я тебе дал пример протокола X11, который работает на любом уровне, будь то unix sockets или ip. Тебе не достаточно? Тогда иди и ищи сам, мне осточертело вправлять мозги таким упёртым теоретикам, нахватавшимся умных слов типа "сериализация". Да в ###у эту сериализацию, когда она не к месту! Достали, честное слово.

logIN
()
Ответ на: комментарий от Zulu

>т.к. клиент и сервер одной архитектуры (имеется в виду byte order)

И чтоб ты знал. Сериализация в поток байтов не спасает от проблем endianness потому, что когда ты будешь приводить два байта в uint16_t, к примеру, тебе все равно придется их swap'ить. А когда к 8 байт к uint64_t то вообще "замучаешься пыль глотать". Поэтому, всегда на уровне протокола оговаривают endianness, если, конечно, протокол не текстовый (аля xml). Именно так сделано для IP протокола, и именно по этой причине IBM гордится, что их Power серверы работают быстрее в сетевых задачах (endianness у них совпадают, оверхеда нету).

logIN
()
Ответ на: комментарий от logIN

logIN :

> Все шлют эти самые бинари данные и ничего...

Ну да, миллионы мух не могут ошибаться...

А, вообще, понятно, почему Линух в последние годы все меньше сам с собой совместим.

Die-Hard ★★★★★
()
Ответ на: комментарий от logIN

logIN (25.10.2005 17:23:15):

> Я тебе дал пример протокола X11...

logIN (25.10.2005 17:31:32):

> ...всегда на уровне протокола оговаривают endianness,...

То есть ты на полном серьезе полагаешь, что на каждый чих прикладной программист вынужден:

1) Тщательно вручную паддить все структуры, написав соответвствующие паддинги для всех возможных настоящих и будущих архитектур (как это сделано в приведенном тобой примере с Иксами);

2) разработать соответствующий миддельварный протокол;

3) стандартизировать его.

Н-да...

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>А, вообще, понятно, почему Линух в последние годы все меньше сам с собой совместим.

А что, solaris уже переписали на java? BSD переписали на lisp? _Все_ посылают структуры. Все! В той или иной мере. Это С(++)! Там нету* прямых методов сериализации потому, что сериализация - это огромнешая степень абстракции. С(++) работают на _низком_ уровне, абстракций там минимум. Поэтому в С(++) никто не боится "стрелять себе в ноги", потому что делают это с умом, думая о каждом байте.

И Linux тут не причем. Хватит жевать одно и то же, надоело. Выкиньте эти тупые мысли, которые вам хрен знает кто вдолбил. Когда надо - структуры можно посылать и их посылают!

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

logIN
()
Ответ на: комментарий от Die-Hard

>Тщательно вручную паддить все структуры

Да в большенстве случаев ничего не надо паддить. Достаточно спроектировать протокол, который будет автоматически выравниваться без остатка на нужных архитектурах (обычно это кратность 16-и или 32-ум). В отличии от выравнивания, от endianness _ничто_ не спасает (кроме как текстовые _однобайтовые_ протоколы. за оверхед тебе не то что ногу прострелят, а руки переломают в пяти местах).

>Н-да...

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

Хватит фигней страдать и дезинформировать, выдывать заведомо ложные постулаты (в данном случае про структуры).

logIN
()
Ответ на: комментарий от logIN

logIN :

> Хватит фигней страдать и дезинформировать, выдывать заведомо ложные постулаты (в данном случае про структуры).

Возвращаю комплимент ;)

Резюме:

Один из нас не прав. И я знаю, кто именно.

Впрочем, ты, наверное, тоже так думаешь:)

Чтож. Аргументы с моей стороны я привел. Аргументы с твоей стороны сводятся к утверждению, что все так делают (что заведомо неверно, поскольку хотя бы _я_ так не делаю;) ).

Думаю, каждый сам сможет сделать выводы. Мне же надоело в 10 раз пересказывать одно и то же...

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>Аргументы с моей стороны я привел.

Да епт, твои аргументы только и состоят из того, что "я так делаю". Проблему ендианнесс ты не решаешь, на оверхед ты плюешь. Что в итоге от твоей сериализации в поток байт? Ничего. Как говорил один профессор - твой суммарный эффект действий свелся к "пшик", не более. То есть, действий ты сделал много, а проблем не решил.

И делай ты как хочешь, делай, другим только не мешай. Не выдывай видимое за действительное. Потому, что видимое - это так, как делаешь ты, не смотря как делют другие, а действительное - это так, как делают все*. Наивно полагать, что ты единственный, ну и, возможно еще с Луговским, Барабаном, Тузиком и другими клоунами, правы. Не подумай, что я сравниваю тебя с ними, но компания единомышленников у тебя именно такая.

* все - это те, чей полезный код доступен, а не губошлепы.

logIN
()
Ответ на: комментарий от logIN

в споре поддержу logIN..

г-да, действительно в сетевых протоколах оговаривается порядок следования байт. И как правило (это не стандарт, это общепринятая практика) байты идут в естественном порядке, а каждая архитектура уже сама их крутит верит, переставлят, чтоб понять.

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

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

Кстати, апалогеты ОО подхода - Вам кагда-нить говорили, что непосредственный доступ к полю класса - зло ? Или Вам приходится буквально руками набирать биты ip заголовков ?? Если говорить про портабельность, то она легче обеспечивается на уровне API чем на уровне данных.

MKuznetsov ★★★★★
()
Ответ на: комментарий от Die-Hard

могу только добавить, что буфер там и не надо. Просто создаёшь объект и считываешь в него поэлементно. Типа

foo a;

fread(&a.a, sizeof(int), 1, fptr);
fread(&a.b, sizeof(short), 1, fptr);
fread(&a.c, sizeof(char), 1, fptr);

Ну и не забыть про размеры типов...

Keiko
()
Ответ на: комментарий от logIN

Кстати

=== Способ 1, Die-Hard:

struct ab {
uint32_t a;
uint16_t b;
uint8_t с;
...
} ab;

struct ab ab1;

recv(x, &ab.a, sizeof(ab.a), 0);
recv(x, &ab.b, sizeof(ab.b), 0);
recv(x, &ab.с, sizeof(ab.с), 0);
recv(...еще куча таких...);

BIG_WORK_HERE;

write(x, ab.a, sizeof(ab.a));
write(x, ab.b, sizeof(ab.b));
write(x, ab.с, sizeof(ab.с));
write(...еще куча таких...);



=== Способ 2, используя packed+aligned;

struct packed_ab {
uint32_t a;
uint16_t b;
uint8_t c;
...
} __attribute__((packed));
struct ab : public packed_ab {} __attribute__((aligned));

struct packed_ab ab1_packed;

recv(x, &ab1_packed, sizeof(ab1_packed), 0);
struct ab ab1 = ab1_packed;

BIG_WORK_HERE;

write(x, &( (packed_ab)ab1 ), sizeof(packed_ab));



То есть, упаковываем только при i/o, все остальное за нас делает компилятор.

Способ 1 будет громоздким при больших структурах, легко потерять какой-то элемент, легко нарушить порядок. Тем более, зачем делать то, что может сделать компилятор? Способ 2 предназначен только для С++.

ЧИТАТЬ ВНИМАТЕЛЬНО: использовать неправильные структуры !вообще! не хорошо. Однако, если приспичило, то есть варианты. Самый простой, это упаковать структуру и вообще ее не распаковывать (это и не Способ 1 и не Способ 2), небольшой оверхед тут обеспечен.
ЧИТАТЬ ЕЩЕ ВНИМАТЕЛЬНЕЕ: С правильными структурами (кратными), таких извращений вообще не нужно - посылай сами структуры куда хочешь, с ними все будет в порядке.

logIN
()
Ответ на: комментарий от logIN

кстати
struct serialized {
  uint16_t encoding_type; // howto low-level parser assembled there
  uint32_t data_type;     // entry to app. data-domain repository
  uint16_t data_length;   // bytes (or entryes) in data
  union data {
    struct serialized *field;
    uint8_t bytecoded[];   // may contain any struct. known by app.
  } data;
}__attribute__((packed));

это заголовок сериализованного эл-та данных (сугубо общий случай чтоб показать принцип)
при передаче над каждым полем htonX, при приёме ntohX..


MKuznetsov ★★★★★
()
Ответ на: комментарий от logIN

> ЧИТАТЬ ЕЩЕ ВНИМАТЕЛЬНЕЕ: С правильными структурами (кратными), таких извращений вообще не нужно - посылай сами структуры куда хочешь, с ними все будет в порядке.

С ними все будет впорядке, если на той стороне будет работать программа в которой компилятор точно также выравнял эту структуру в памяти. Кто мне это гарантирует ?

anonymous
()
Ответ на: комментарий от anonymous

>Кто мне это гарантирует ?

генерируемый config.h (через autotools или любые другие building tools) + #define тебе это гарантируют. Так делают _везде_ и лучшего способа пока не придумали. Средства для упаковки/выравнивания есть в любом компиляторе.

То есть

#ifdef MSVC
#define ALIGNED blabla (хз что там ;-)
#else
#define ALIGNED __attribute__ ((aligned))
#endif

struct { ... } ALIGNED;

logIN
()
Ответ на: комментарий от anonymous

> С ними все будет впорядке, если на той стороне будет работать программа в которой компилятор точно также выравнял эту структуру в памяти. Кто мне это гарантирует ?

Блин, да ты же и гарантируешь. Написав прикладной уровень по разбору твоей структуры, либо описав формат упомянутой херни..

У вас вообще бывали лекции по теории передачи информации ? так вот чтобы приёмник мог понять о чём шепелявит передатчик он(приёмник) должен иметь некоторое понятие о том что же именно шепелявится..

MKuznetsov ★★★★★
()
Ответ на: комментарий от logIN

> Средства для упаковки/выравнивания есть в любом компиляторе.

Зачем ты лжешь, смешное существо? Найди эти средства в Sun Workshop на Спарке...

anonymous
()
Ответ на: комментарий от logIN

logIN (*) (25.10.2005 21:05:43):

Да уж...

> === Способ 1, Die-Hard:

Я такого не предлагал.

> === Способ 2, используя packed+aligned

Немного подумав (если, конечно, есть _чем_ :) ), нетрудно понять, что этот способ и есть пересылка через буфер (простейшая сериализация, про которую я и говорил), выполненная череззадничным компиляторозависимым способом.

Короче, IMHO спорить тут не о чем, все сказано. Я не пионервожатый, чтобы убеждать детишек через дорогу не бегать ;)

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>Я такого не предлагал.

В прошлом треде, мы именно об этом способе и говорили. И оверхед у такого способа приличный.

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

Причем, очень даже читабельная и понятная. Однако, еще и еще раз: упаковки лучше избегать вообще, а писать/читать нормальные, кратные структуры.

>все сказано.

Вот уж точно. Ваши постулаты ничем не подкреплены.

logIN
()
Ответ на: комментарий от logIN

Братья, позвольте я подытожу все вышесказанное

1. кратные структуры (имеется ввиду кратные 2 в втепени n ?) можно читать/писать без проблем
2. упаковку структур желательно избегать
3. если все же требуется читать/писать данные из "некратной" (скажем так) структуры, то данные сначала лучше загнать в неструктурированный буфер (например char) и дальше оперировать этим буфером, чем применять упаковку структуры

Поправьте, если что не так.

PS
Давайте не будем устраивать спор, чьё кунгфу круче, прошу конструктивный диалог, за и против :)

anonymous
()
Ответ на: комментарий от anonymous

>неструктурированный буфер (например char) и дальше оперировать этим буфером, чем применять упаковку структуры

Как я уже указал в Способ 1 и Способ 2 - "буфер" из char и упаковка это практически одно и тоже. Только, если первое делается вручную, то второе автоматически компилятором. А так, все верно.

>упаковку структур желательно избегать

Желательно, но упакованые структуры тоже находят применение. Что быстрее, мучить IO, или быстро прочитать в упакованые структуры. Узкое место обычно это IO, а не CPU/RAM, поэтому бывает быстрее сразу прочитать много (mmap), чем возиться с этим. Но в общем случае, все три метода имеют право на жизнь, и все так или иначе применяются.

>чьё кунгфу круче

Моё круче, ясен пень. ;-) До этого вообще говорили что "нельзя!".

logIN
()
Ответ на: комментарий от anonymous

#pragma pack(push,1) 
struct some_struct 
{
 char a[2];
 int b;
}; 
#pragma pack(pop) 
Работает в MSVC и gcc3 

anonymous
()
Ответ на: комментарий от logIN

> Желательно, но упакованые структуры тоже находят применение. Что быстрее, мучить IO, или быстро прочитать в упакованые структуры. Узкое место обычно это IO, а не CPU/RAM, поэтому бывает быстрее сразу прочитать много (mmap), чем возиться с этим.

Теперь понятно. У вас mmap перемещает данные минуя IO. А с упакованными структурами настоятельно советую поработать на не-интельных машинах. Первые несколько address errors быстро отрезвляют.

vnp
()
Ответ на: комментарий от anonymous

anonymous (*) (26.10.2005 2:07:31):

> 1. кратные структуры (имеется ввиду кратные 2 в втепени n ?) можно читать/писать без проблем

Да нет, конечно.

Писать можно только выровненные на некую специфическую для конкретной архитектуры длину (часто -- длина машинного слова) структуры, и только если хорошо знаешь, что делаешь. Очень редко такое бывает нужно, как правило, либо в железоспецифических вещах, либо низкоуровневых системных/миддлеварных, типа драйверов для ФС или упоминавшихся тут Иксов.

Общее правило: структуры не читать/писать вообще. Исключения -- см. выше.

> 2. упаковку структур желательно избегать

Да. Без исключений. Упакованные структуры не нужны.

Хотя слово "желательно" тут упомянуто к месту: например, требуется быстренько слабать разовую программулину под конкретный компилер...

> 3. если все же требуется читать/писать данные из "некратной" (скажем так) структуры, то данные сначала лучше загнать в неструктурированный буфер (например char) и дальше оперировать этим буфером, чем применять упаковку структуры

Это для _любой_ структуры справедливо.

Die-Hard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.