sizeof объединение в C/C++

Это само по себе не отвечает на вопрос, но вы можете избавиться от вашего конкретного предупреждения по проекту, если добавите в свой composer.json следующее:

"extra": {
    "symfony": {
        "allow-contrib": true
    }
}

или, что еще лучше, вы можете используйте сам Composer для установки флага перед установкой symfony/apache-pack:

composer config extra.symfony.allow-contrib true

Это позволит Flex автоматически устанавливать рецепты вклада (т.е. рецепты, предоставленные сообществом) автоматически, без запроса разрешения.

41
задан timrau 14 August 2012 в 17:52
поделиться

7 ответов

The Standard answers all questions in section 9.5 of the C++ standard, or section 6.5.2.3 paragraph 5 of the C99 standard (or paragraph 6 of the C11 standard, or section 6.7.2.1 paragraph 16 of the C18 standard):

In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time. [Note: one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members; see 9.2. ] The size of a union is sufficient to contain the largest of its data members. Each data member is allocated as if it were the sole member of a struct.

That means each member share the same memory region. There is at most one member active, but you can't find out which one. You will have to store that information about the currently active member yourself somewhere else. Storing such a flag in addition to the union (for example having a struct with an integer as the type-flag and an union as the data-store) will give you a so called "discriminated union": An union which knows what type in it is currently the "active one".

One common use is in lexers, where you can have different tokens, but depending on the token, you have different informations to store (putting line into each struct to show what a common initial sequence is):

struct tokeni {
    int token; /* type tag */
    union {
        struct { int line; } noVal;
        struct { int line; int val; } intVal;
        struct { int line; struct string val; } stringVal;
    } data;
};

The Standard allows you to access line of each member, because that's the common initial sequence of each one.

There exist compiler extensions that allow accessing all members disregarding which one currently has its value stored. That allows efficient reinterpretation of stored bits with different types among each of the members. For example, the following may be used to dissect a float variable into 2 unsigned shorts:

union float_cast { unsigned short s[2]; float f; };

That can come quite handy when writing low-level code. If the compiler does not support that extension, but you do it anyway, you write code whose results are not defined. So be certain your compiler has support for it if you use that trick.

30
ответ дан AJM-Reinstate-Monica 27 November 2019 в 00:13
поделиться

Не существует понятия активного типа данных для объединения. Вы можете читать и писать любому «члену» объединения: вам решать, что вы получите.

Следовательно, размер объединения всегда равен размеру его самого большого типа данных.

11
ответ дан mouviciel 27 November 2019 в 00:13
поделиться

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

union {
  short x;
  int y;
  long long z;
}

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

Дополнительное примечание : Как отметил Стефано , фактическое пространство любого типа ( union , struct , class ) будет зависеть от других вопросов такие как выравнивание компилятором. Я не прошел через это для простоты, так как я просто хотел сказать, что профсоюз принимает во внимание самый большой элемент. Важно знать, что фактический размер действительно зависит от выравнивания .

58
ответ дан Community 27 November 2019 в 00:13
поделиться

Размер будет по крайней мере такого же размера, как у самого большого типа сочинения. Не существует понятия «активный» тип.

3
ответ дан 27 November 2019 в 00:13
поделиться

Зависит от компилятора и опций.

int main() {
  union {
    char all[13];
    int foo;
  } record;

printf("%d\n",sizeof(record.all));
printf("%d\n",sizeof(record.foo));
printf("%d\n",sizeof(record));

}

Выводит:

13 4 16

Если я правильно помню, это зависит от выравнивания, которое компилятор помещает в выделенное пространство. Поэтому, если вы не используете какую-либо специальную опцию, компилятор поместит отступ в пространство объединения.

edit: с gcc вам нужно использовать директиву pragma

int main() {
#pragma pack(push, 1)
      union {
           char all[13];
           int foo;
      } record;
#pragma pack(pop)

      printf("%d\n",sizeof(record.all));
      printf("%d\n",sizeof(record.foo));
      printf("%d\n",sizeof(record));

}

, которая выводит

13 4 13

Вы также можете увидеть это из дизассемблирования (убрал часть printf, для ясности)

  0x00001fd2 <main+0>:    push   %ebp             |  0x00001fd2 <main+0>:    push   %ebp
  0x00001fd3 <main+1>:    mov    %esp,%ebp        |  0x00001fd3 <main+1>:    mov    %esp,%ebp
  0x00001fd5 <main+3>:    push   %ebx             |  0x00001fd5 <main+3>:    push   %ebx
  0x00001fd6 <main+4>:    sub    $0x24,%esp       |  0x00001fd6 <main+4>:    sub    $0x24,%esp
  0x00001fd9 <main+7>:    call   0x1fde <main+12> |  0x00001fd9 <main+7>:    call   0x1fde <main+12>
  0x00001fde <main+12>:   pop    %ebx             |  0x00001fde <main+12>:   pop    %ebx
  0x00001fdf <main+13>:   movl   $0xd,0x4(%esp)   |  0x00001fdf <main+13>:   movl   $0x10,0x4(%esp)                                         
  0x00001fe7 <main+21>:   lea    0x1d(%ebx),%eax  |  0x00001fe7 <main+21>:   lea    0x1d(%ebx),%eax
  0x00001fed <main+27>:   mov    %eax,(%esp)      |  0x00001fed <main+27>:   mov    %eax,(%esp)
  0x00001ff0 <main+30>:   call  0x3005 <printf>   |  0x00001ff0 <main+30>:   call   0x3005 <printf>
  0x00001ff5 <main+35>:   add    $0x24,%esp       |  0x00001ff5 <main+35>:   add    $0x24,%esp
  0x00001ff8 <main+38>:   pop    %ebx             |  0x00001ff8 <main+38>:   pop    %ebx
  0x00001ff9 <main+39>:   leave                   |  0x00001ff9 <main+39>:   leave
  0x00001ffa <main+40>:   ret                     |  0x00001ffa <main+40>:   ret    

Где единственное отличие - в main + 13, где компилятор размещает в стеке 0xd вместо 0x10

17
ответ дан Stefano Borini 27 November 2019 в 00:13
поделиться

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

Вы часто видите, что это используется в сочетании с вызовами ioctl () в Unix, все вызовы ioctl () будут проходить одну и ту же структуру, которая содержит объединение всех возможных ответов. Например этот пример взят из /usr/include/linux/if.h, и эта структура используется в ioctl () для настройки / запроса состояния интерфейса Ethernet, параметры запроса определяют, какая часть объединения фактически используется:

struct ifreq 
{
#define IFHWADDRLEN 6
    union
    {
        char    ifrn_name[IFNAMSIZ];        /* if name, e.g. "en0" */
    } ifr_ifrn;

    union {
        struct  sockaddr ifru_addr;
        struct  sockaddr ifru_dstaddr;
        struct  sockaddr ifru_broadaddr;
        struct  sockaddr ifru_netmask;
        struct  sockaddr ifru_hwaddr;
        short   ifru_flags;
        int ifru_ivalue;
        int ifru_mtu;
        struct  ifmap ifru_map;
        char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
        char    ifru_newname[IFNAMSIZ];
        void *  ifru_data;
        struct  if_settings ifru_settings;
    } ifr_ifru;
};
2
ответ дан amo-ej1 27 November 2019 в 00:13
поделиться
  1. The size of the largest member.

  2. This is why unions usually make sense inside a struct that has a flag that indicates which is the "active" member.

Example:

struct ONE_OF_MANY {
    enum FLAG { FLAG_SHORT, FLAG_INT, FLAG_LONG_LONG } flag;
    union { short x; int y; long long z; };
};
0
ответ дан Mehrdad Afshari 27 November 2019 в 00:13
поделиться