Re[8]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 15.01.10 14:05
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Skorodum, Вы писали:


R>>>Во-вторых, типы нулевых массивов должны влиять и на размер структуры. Это необходимо для работы идиомы выделения таких объектов — "malloc(sizeof(X) + sizeof(Y) * N)".

R>>>Т.е. в таком коде, включив или bar или baz, ты получишь разный sizeof(X):
R>>>
R>>>struct X
R>>>{
R>>>  char foo [1];
R>>>  //char bar [0];
R>>>  //int  baz [0];
R>>>};
R>>>


S>>То же самое, gcc показывает что не зависит. Нулевые массивы не добавляют к структуре ничего.


R>Хммм... что-то я не уверен. Как так может быть? Тогда "malloc(sizeof(X) + sizeof(Y) * N)" не будет работать, а именно так все и пишут. Смысла тогда добавлять такую поддержку нулевых массивов мало...

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

Я вот не понимаю зачем несколько таких нулевых массивов может понадобиться
Re[9]: struct has an illegal zero-sized array
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 14:28
Оценка:
Здравствуйте, Skorodum, Вы писали:

R>>Хммм... что-то я не уверен. Как так может быть? Тогда "malloc(sizeof(X) + sizeof(Y) * N)" не будет работать, а именно так все и пишут. Смысла тогда добавлять такую поддержку нулевых массивов мало...

S>Вы же сами написали: надо заморачиваться с выравниванием. В линухе используют макросы для этого.

S>Я вот не понимаю зачем несколько таких нулевых массивов может понадобиться


Потому что они влияют и на адрес и на размер структруры. Не наводите, пожалуйста, тень на плетень со старым компилятором.

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>

struct Y
{
  char ch;
};

struct X
{
  char     ch;
  char     arr1 [0];
  int      arr2 [0];
  double   arr3 [0];
};

typedef struct X X_t;

int main()
{
  printf("sizeof(Y)=%u\n", sizeof(struct Y));
  printf("sizeof(X)=%u\n", sizeof(struct X));
  printf("offsetof(arr1)=%u\n", offsetof(X_t, arr1));
  printf("offsetof(arr2)=%u\n", offsetof(X_t, arr2));
  printf("offsetof(arr3)=%u\n", offsetof(X_t, arr3));
  return 0;
}


[test]$ gcc -v
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)
[test]$ gcc test.c -o test -malign-double
[test]$ ./test
sizeof(Y)=1
sizeof(X)=8
offsetof(arr1)=1
offsetof(arr2)=4
offsetof(arr3)=8




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: struct has an illegal zero-sized array
От: Кодт Россия  
Дата: 15.01.10 14:28
Оценка:
Здравствуйте, Skorodum, Вы писали:

S>Поясните, пожалуйста, подробнее зачем таких переменных больше одной?


Ну, как бы, на примере
struct rgb555  { unsigned char r:5, g:6, b:5; }; // 16-bit
struct rgb888  { unsigned char r, g, b; };
struct rgba888 { unsigned char r, g, b, a; };

struct my_bitmap_header
{
  unsigned short signature;
  enum { monochrome, palette, hicolor, truecolor, alphatruecolor } type;
  int width, height;

  // union {
    unsigned short bits[0]; // в монохромной картинке пикселы сгруппированы по 2 байта
    unsigned char  pixels_pal[0];
    rgb565         pixels_hc[0];
    rgb888         pixels_tc[0];
    rgba888        pixels_tca[0];
  // };
};

Без union — VC не скомпилирует, с union — допишет в конец структуры один лишний пиксел самого большого размера.
В общем, спасибо, что под линуксом один "главный" компилятор, а не разброд и шатания, как в мире закрытых окон.

А пользуются этим добром вот так:
unsigned char *raw_bmp;
// грузим его из файла

my_bitmap_header* bmp = (my_bitmap_header*)raw_bmp;
switch(bmp->type)
{
case truecolor:
   // работаем с bmp->pixels_tc[]
}
Перекуём баги на фичи!
Re[6]: struct has an illegal zero-sized array
От: gear nuke  
Дата: 15.01.10 14:31
Оценка:
Здравствуйте, remark, Вы писали:

R>Синтаксический сахар за борт, полагаю, что типы нулевых массивов влияют на выравнивание.


Не знаю как у *nix, но в ядре Винды все выравнивания обычно делаются за счёт явных dummy полей (и вообще тщательно выбирается место для полей разного размера).

Структуру с несколькими типами в конце сходу не вспомню, но для доступа к таким полям используют:
#define MmGetMdlPfnArray(Mdl) ((PPFN_NUMBER)(Mdl + 1))

Многие структуры в доке описаны как opaque + макросы для доступа:
#define NDIS_PACKET_EXTENSION_FROM_PACKET(_P)       ((PNDIS_PACKET_EXTENSION)((PUCHAR)(_P) + (_P)->Private.NdisPacketOobOffset + sizeof(NDIS_PACKET_OOB_DATA)))
#define NDIS_PER_PACKET_INFO_FROM_PACKET(_P, _Id)   ((PNDIS_PACKET_EXTENSION)((PUCHAR)(_P) + (_P)->Private.NdisPacketOobOffset + sizeof(NDIS_PACKET_OOB_DATA)))->NdisPacketInfo[(_Id)]
#define NDIS_GET_ORIGINAL_PACKET(_P)                NDIS_PER_PACKET_INFO_FROM_PACKET(_P, OriginalPacketInfo)
#define NDIS_SET_ORIGINAL_PACKET(_P, _OP)           NDIS_PER_PACKET_INFO_FROM_PACKET(_P, OriginalPacketInfo) = _OP
#define NDIS_GET_PACKET_CANCEL_ID(_P)               NDIS_PER_PACKET_INFO_FROM_PACKET(_P, PacketCancelId)
#define NDIS_SET_PACKET_CANCEL_ID(_P, _cId)         NDIS_PER_PACKET_INFO_FROM_PACKET(_P, PacketCancelId) = _cId
наверное, private в C нет...
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[10]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 15.01.10 14:33
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Skorodum, Вы писали:


S>>Здравствуйте, remark, Вы писали:


R>>>А если а объявить как char, а не как int?


S>>no difference


S>>gcc version 3.4.5


R>Не может так быть.


R>
R>#include <stdio.h>
R>#include <stdint.h>

R>struct Y
R>{
R>  char ch;
R>};

R>struct X
R>{
R>  char ch;
R>  uint64_t arr [0];
R>};

R>int main()
R>{
R>  printf("sizeof(Y)=%u\n", sizeof(Y));
R>  printf("sizeof(X)=%u\n", sizeof(X));
R>}
R>


R>

R>g++ -v
R>gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

R>sizeof(Y)=1
R>sizeof(X)=4


R>Просто баг в gcc 3.4.5. Проапдейть до более новой версии.


Все верно, если первый и единственный член — char, то разница есть. Но, 4 != sizeof(char) + sizeof(uint64_t*). Более того, если добавить еще нулевых указателей, размер не изменится. Наверное, изменение размера связано с необходимостью выравнивания.
Re[11]: struct has an illegal zero-sized array
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 14:35
Оценка:
Здравствуйте, Skorodum, Вы писали:

R>>Просто баг в gcc 3.4.5. Проапдейть до более новой версии.


S>Все верно, если первый и единственный член — char, то разница есть. Но, 4 != sizeof(char) + sizeof(uint64_t*). Более того, если добавить еще нулевых указателей, размер не изменится. Наверное, изменение размера связано с необходимостью выравнивания.


Именно.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[10]: struct has an illegal zero-sized array
От: Кодт Россия  
Дата: 15.01.10 14:37
Оценка:
Здравствуйте, remark, Вы писали:

R>Потому что они влияют и на адрес и на размер структруры. Не наводите, пожалуйста, тень на плетень со старым компилятором.


R>gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

R>[test]$ gcc test.c -o test -malign-double
R>[test]$ ./test
R>sizeof(Y)=1
R>sizeof(X)=8
R>offsetof(arr1)=1
R>offsetof(arr2)=4
R>offsetof(arr3)=8

Тот же самый результат, gcc 3.4.4 (cygwin), без -malign-double
Перекуём баги на фичи!
Re[11]: struct has an illegal zero-sized array
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 14:38
Оценка:
Здравствуйте, Skorodum, Вы писали:
R>>Просто баг в gcc 3.4.5. Проапдейть до более новой версии.

S>Все верно, если первый и единственный член — char, то разница есть. Но, 4 != sizeof(char) + sizeof(uint64_t*). Более того, если добавить еще нулевых указателей, размер не изменится.


Изменится. И не только размер структуры, но и адреса этих самых нулевых массивов.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: struct has an illegal zero-sized array
От: gear nuke  
Дата: 15.01.10 14:42
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Нифига не супер. Съесть-то она съест, только посчитает [1] вместо [0].


Я уже проверить не могу, но это возможно от версии компилятора, или каких-то ключей зависит. По крайней мере раньше работал такой код:
class type_info
{
// ...
  private:
    mutable void* data;
    char    mname[1];
};

а потом пришлось изменить на:
class type_info
{
// ...
  private:
    mutable void* data;
    const char* mname() const { return reinterpret_cast<const char*>(this + 1); }
};
#if defined(_MSC_VER) && !defined(__ICL)
///\warning break this to get `Unresolved external : const type_info::'vftable' (??_7type_info@@6B@)`
static_assert(sizeof _TypeDescriptor == sizeof type_info, "broken type");
#endif

К>То есть, для интерпретации уже готового пакета как заголовок+хвост это пригодно, а для построения такого пакета — увы.

Да, опасная штука.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[10]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 15.01.10 14:56
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Skorodum, Вы писали:


R>>>Хммм... что-то я не уверен. Как так может быть? Тогда "malloc(sizeof(X) + sizeof(Y) * N)" не будет работать, а именно так все и пишут. Смысла тогда добавлять такую поддержку нулевых массивов мало...

S>>Вы же сами написали: надо заморачиваться с выравниванием. В линухе используют макросы для этого.

S>>Я вот не понимаю зачем несколько таких нулевых массивов может понадобиться


R>Потому что они влияют и на адрес и на размер структруры. Не наводите, пожалуйста, тень на плетень со старым компилятором.


gcc version 3.4.5

sizeof(Y)=1
sizeof(X)=4
offsetof(arr1)=1
offsetof(arr2)=4
offsetof(arr3)=4


...но еще нулевых массивов и результат не меняется, где же память под новые указатели?...

struct X
{
  char     ch;
  char     arr1 [0];
  int      arr2 [0];
  double   arr3 [0];
  int      arr4 [0];
  char     arr5 [0];
};

typedef struct X X_t;

int main()
{
  printf("sizeof(Y)=%u\n", sizeof(struct Y));
  printf("sizeof(X)=%u\n", sizeof(struct X));
  printf("offsetof(arr1)=%u\n", offsetof(X_t, arr1));
  printf("offsetof(arr2)=%u\n", offsetof(X_t, arr2));
  printf("offsetof(arr3)=%u\n", offsetof(X_t, arr3));
  printf("offsetof(arr3)=%u\n", offsetof(X_t, arr4));
  printf("offsetof(arr3)=%u\n", offsetof(X_t, arr5));
  return 0;
}


sizeof(Y)=1
sizeof(X)=8
offsetof(arr1)=1
offsetof(arr2)=4
offsetof(arr3)=8
offsetof(arr4)=8
offsetof(arr5)=8

Re[11]: struct has an illegal zero-sized array
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 14:59
Оценка:
Здравствуйте, Skorodum, Вы писали:

S>...но еще нулевых массивов и результат не меняется, где же память под новые указатели?...


А почему ты думаешь, что они должны занимать память?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[12]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 15.01.10 15:00
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Skorodum, Вы писали:


R>>>Просто баг в gcc 3.4.5. Проапдейть до более новой версии.


S>>Все верно, если первый и единственный член — char, то разница есть. Но, 4 != sizeof(char) + sizeof(uint64_t*). Более того, если добавить еще нулевых указателей, размер не изменится. Наверное, изменение размера связано с необходимостью выравнивания.


R>Именно.


Т.е.

struct Foo
{
   char ch;
   char a[0]; //будет содержать адрес куда можно записывать char
   int b[0]; //будет содержать адрес куда можно записывать int
   double c[0]; //будет содержать адрес куда можно записывать double
   ...
};


R>
Re[13]: struct has an illegal zero-sized array
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 15:04
Оценка:
Здравствуйте, Skorodum, Вы писали:

S>Т.е.

S>

S>struct Foo
S>{
S>   char ch;
S>   char a[0]; //будет содержать адрес куда можно записывать char
S>   int b[0]; //будет содержать адрес куда можно записывать int
S>   double c[0]; //будет содержать адрес куда можно записывать double
S>   ...
S>};
S>


Если это был вопрос, то — да. Адрес 'a' подходит для записи/чтения чаров, 'b' — интов, 'c' — даблов. Очевидно, что адрес, который подходит для записи/чтения чаров, может не подходить для записи/чтения даблов.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[12]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 15.01.10 15:05
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Skorodum, Вы писали:


S>>...но еще нулевых массивов и результат не меняется, где же память под новые указатели?...


R>А почему ты думаешь, что они должны занимать память?


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

R>
Re[14]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 15.01.10 15:10
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Skorodum, Вы писали:


S>>Т.е.

S>>

S>>struct Foo
S>>{
S>>   char ch;
S>>   char a[0]; //будет содержать адрес куда можно записывать char
S>>   int b[0]; //будет содержать адрес куда можно записывать int
S>>   double c[0]; //будет содержать адрес куда можно записывать double
S>>   ...
S>>};
S>>


R>Если это был вопрос, то — да. Адрес 'a' подходит для записи/чтения чаров, 'b' — интов, 'c' — даблов. Очевидно, что адрес, который подходит для записи/чтения чаров, может не подходить для записи/чтения даблов.


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

R>
Re[6]: struct has an illegal zero-sized array
От: Skorodum Россия  
Дата: 16.01.10 05:02
Оценка:
Здравствуйте, Кодт, Вы писали:

Спасибо, разжевали.

Мне приходилось сталкиваться только со случаем, когда в качестве данных — набор элементов неизвестной и переменной длины. Естественно, все выравнено по максимуму и нулевые массивы любых типов указывают на один и тот же адрес, вот до меня долго и доходило зачем их может несколько понадобиться. Век живи — век учись!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.