0

My question is based off a part of this wiki answer to the question of Why isn't sizeof for a struct equal to the sum of sizeof of each member? (emphasize mine):

"IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings."

  • Is it possible to detect and change the current structure alignment setting in gcc/g++?
  • And if so, How do I detect the current alignment setting + how can I change it in gcc/g++?

Thank you very much for your help.

  • 1
    Just specify the alignment explicitly with `__attribute__ ((aligned (x)))` so no need to detect anything. – Eugene Sh. Feb 20 '20 at 16:43
  • 2
    Pretty sure it's about `__attribute__((packed))` (which should be banned). – EOF Feb 20 '20 at 16:44
  • @EOF Most embedded devs will suffer if you ban it. – Eugene Sh. Feb 20 '20 at 16:45
  • 1
    @EugeneSh. because they have to think about the order of their struct members? Because they prefer torturing their load/store units in the microprocessor to make up for tiny amounts of memory? – EOF Feb 20 '20 at 16:48
  • @EOF mainly because of the frequent need to serialize the data over communication channels. Between machines that might have different architectures too. – Eugene Sh. Feb 20 '20 at 16:50
  • @EugeneSh. Thank you very much. Is there a way to determine the "basic" alignment setting for structures with a console command f.e.? – RobertS supports Monica Cellio Feb 20 '20 at 16:52
  • 1
    @EugeneSh. `__attribute__((packed))` is not an adequate substitute for proper serialization. – EOF Feb 20 '20 at 16:52
  • @EOF You do not have to use it. – 0___________ Feb 20 '20 at 16:53
  • @P__J__ I might want to gouge out my eyes if I keep seeing it in code I have to use. – EOF Feb 20 '20 at 16:54
  • @EOF pretty sure you never program uCs – 0___________ Feb 20 '20 at 16:55
  • @P__J__ We can all be sure of incorrect things. – EOF Feb 20 '20 at 16:56
  • @EOF As a frequent user of SO I know this :) But I am also an experienced embedded developer communicating with many others (sometimes experienced too) who would not agree :) – Eugene Sh. Feb 20 '20 at 16:56
  • @EOF same as you :) – 0___________ Feb 20 '20 at 16:56
  • @EOF What would be your preferred alternative to do in C? – RobertS supports Monica Cellio Feb 20 '20 at 17:18
  • 1
    @RobertSsupportsMonicaCellio Write a function that serializes your data into a `uint8_t`-array. Better yet, define a grammar for the serialized format, autogenerate the code, for both serializing and deserializing, so you don't have any mismatch, neither between serializing and deserializing, nor among different architectures. – EOF Feb 20 '20 at 17:20
  • 1
    @EOF Indeed. [`__attribute__((packed))` is dangerous](https://stackoverflow.com/questions/8568432/is-gccs-attribute-packed-pragma-pack-unsafe) and [any misaligned access can blow up even on x86](https://stackoverflow.com/questions/46790550/c-undefined-behavior-strict-aliasing-rule-or-incorrect-alignment/46790815#46790815). It's a bit dispiriting to see people pushing for writing code that can fail just by merely changing the optimization level on a "forgiving" platform such as x86. Does the coder maintaining such code in 5 years "know what they're doing"? – Andrew Henle Feb 20 '20 at 17:28
  • @AndrewHenle Thank you very much for the provided links. Would you implement an alternative like the one ` EOF` has explained or would go for another permissible way or even avoiding doing any kind of "re-allignments" and leave everything as it were allocated by default by the compiler? – RobertS supports Monica Cellio Feb 20 '20 at 17:40
  • @EugeneSh. What would you say about [Andrew Heinle´s comment](https://stackoverflow.com/questions/60324755/can-i-detect-and-change-the-current-data-alignment-setting-for-structures-in-gcc?noredirect=1#comment106711119_60324755) and the linked SO posts about `__attribute__((packed))` being considered as dangerous? – RobertS supports Monica Cellio Feb 20 '20 at 17:49
  • 1
    @RobertSsupportsMonicaCellio I fully agree with it from a theoretical standpoint, but from practical one I have seen *huge* amounts of code making use of it and would think that the maintainers of it would not agree to change it. – Eugene Sh. Feb 20 '20 at 17:56

2 Answers2

2

Is it possible to ... change the current structure alignment setting in gcc/g++?

Yes. GCC pragmas and command line options are described in GCC documentation.

There is a command line option:

-fpack-struct[=n]

Without a value specified, pack all structure members together without holes. When a value is specified (which must be a small power of two), pack structure members according to this value, representing the maximum alignment (that is, objects with default alignment requirements larger than this are output potentially unaligned at the next fitting location.

Warning: the -fpack-struct switch causes GCC to generate code that is not binary compatible with code generated without that switch. Additionally, it makes the code suboptimal. Use it to conform to a non-default application binary interface.

And pragmas:

For compatibility with Microsoft Windows compilers, GCC supports a set of #pragma directives which change the maximum alignment of members of structures (other than zero-width bitfields), unions, and classes subsequently defined. The n value below always is required to be a small power of two and specifies the new alignment in bytes.

  1. #pragma pack(n) simply sets the new alignment.
  2. #pragma pack() sets the alignment to the one that was in effect when compilation started (see also command line option -fpack-struct[=] see Code Gen Options).
  3. #pragma pack(push[,n]) pushes the current alignment setting on an internal stack and then optionally sets the new alignment.
  4. #pragma pack(pop) restores the alignment setting to the one saved at the top of the internal stack (and removes that stack entry). Note that #pragma pack([n]) does not influence this internal stack; thus it is possible to have #pragma pack(push) followed by multiple #pragma pack(n) instances and finalized by a single #pragma pack(pop).

Some targets, e.g. i386 and powerpc, support the ms_struct #pragma which lays out a structure as the documented __attribute__ ((ms_struct)).

  1. #pragma ms_struct on turns on the layout for structures declared.
  2. #pragma ms_struct off turns off the layout for structures declared.
  3. #pragma ms_struct reset goes back to the default layout.

Is it possible to detect ... the current structure alignment setting in gcc/g++?

Depends a lot on what you mean by "detect". There is following command line option:

-frecord-gcc-switches

This switch causes the command line that was used to invoke the compiler to be recorded into the object file that is being created. This switch is only implemented on some targets and the exact format of the recording is target and binary file format dependent, but it usually takes the form of a section containing ASCII text.

If such option was used, then you can detect whether -fpack-struct[=n] was used by inspecting the binary.


If you simply want to know the alignment of a particular type, you can use the alignof operator. If you want to know the maximum alignment of any scalar type, you can use alignof(std::max_align_t). You can specify classes or arrays to have stricter alignment than they would otherwise have with alignas. If that exceeds the alignment of std::max_align_t, then the class is said to be over-aligned.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

For C++, starting in C++11 you can use alignas and alignof to portably set and get the alignment of any type. Below is the example from cppreference for alignof where you can see both in action:

#include <iostream>

struct Foo {
    int   i;
    float f;
    char  c;
};

struct Empty {};

struct alignas(64) Empty64 {};

int main()
{
    std::cout << "Alignment of"  "\n"
        "- char             : " << alignof(char)    << "\n"
        "- pointer          : " << alignof(int*)    << "\n"
        "- class Foo        : " << alignof(Foo)     << "\n"
        "- empty class      : " << alignof(Empty)   << "\n"
        "- alignas(64) Empty: " << alignof(Empty64) << "\n";
}

Possible output:

Alignment of
- char             : 1
- pointer          : 8
- class Foo        : 4
- empty class      : 1
- alignas(64) Empty: 64

It should be noted that alignas won't let you use an alignment that is less strict then what the object would need by default. This means you can't use it to "pack", remove the padding, of a data structure.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Thank you very much. That is very useful. Do you know about a specific command-line command with which I could alter the "basic" alignment setting for structures in g++? Or can I only do get and specify it in the source code of a particular C++ program? – RobertS supports Monica Cellio Feb 20 '20 at 17:02
  • 1
    @RobertSsupportsMonicaCellio Looks like eerorika beat me to that information. See their answer. – NathanOliver Feb 20 '20 at 17:07
  • BTW, Since it is C++11, This shall be compatible with other C++11-conform compilers, such as clang, too, right? – RobertS supports Monica Cellio Feb 20 '20 at 17:13
  • 1
    @RobertSsupportsMonicaCellio Yep. Any C++11 compliant compiler will support this. That's mostly why I added it so you could have a portable option if you didn't actually need to pack the structures, but just guarantee their alignment. – NathanOliver Feb 20 '20 at 17:14