0

Good evening!

'Got the following problem: I have an input stream of multi- and single-byte datatypes and just want to lay it over a struct. Unfortunately, if I put an uneven amount of 8bit members in a struct together with 16bit members, the sizeof() function will give me the round up to an even length.

Following example:

Datatypes:

struct uuu { // should contain 5 bytes
    uint8_t a[1];
    uint8_t b[1];
    uint16_t c;
    char d[1];
};
struct ccc { // should contain 5 bytes
    char a;
    char b;
    char c;
    uint16_t d;
};
struct bbb { // should contain 3 bytes
    char a;
    char b;
    char c;
};

Snippet:

printf("char_bit: %d\n", CHAR_BIT);
printf("%d | %d | %d", sizeof(uuu), sizeof(ccc), sizeof(bbb));

Result:

char_bit: 8
6 | 6 | 3

The point is, I need an exact order of 8bit member to parse the stream into the predefined struct. Is there a way to force this? Working on a 64bit machine, tried already compiling with the -m32 gcc flag.

I know it has to do with paddings of struct etc. But is there a workaround to still achieve the fixed structure sizes?

Thanks in advance!

TeStUn.De
  • 3
  • 4
  • 1
    I think you're looking for the words "structure packing" and "alignment." That might help you find what you're looking for. – templatetypedef Oct 09 '17 at 02:35
  • [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](https://stackoverflow.com/q/119123/995714) – phuclv Oct 09 '17 at 02:44
  • Just write code to do what you need. If you care about the size of the structure, you're doing something wrong. – David Schwartz Oct 09 '17 at 02:57
  • @DavidSchwartz The structure of the incoming stream is predefined and not quite small, so it is easier to use this method. – TeStUn.De Oct 09 '17 at 03:19
  • @TeStUn.De It's predefined to always match whatever your compiler happens to like to use as a layout or representation? And you only care about platforms that fully support unaligned accesses? – David Schwartz Oct 09 '17 at 03:20
  • @DavidSchwartz the program I am writing is only for those systems, yes – TeStUn.De Oct 09 '17 at 03:50

1 Answers1

0

If you use the packed attribute, your structs will not contain padding.

struct __attribute__((packed)) uuu { // will now contain 5 bytes
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • 1
    Right, because: the language makes no guarantees. What the author wants isn't portable C. But in this case the compiler is willing to do him a favour. – Tommy Oct 09 '17 at 02:39
  • Re "*What the author wants isn't portable C*", Furthermore, some machines are not actually capable of accessing certain types unless they are properly aligned. – ikegami Oct 09 '17 at 02:45
  • This will cause your accesses to be unaligned which could cause your code to crash or otherwise do the wrong thing. – David Schwartz Oct 09 '17 at 02:58
  • @Tommy It is not portable, but we don't know that portability is a requirement for the OP's project, since such a constraint was not mentioned. Unaligned accesses *are* allowed on many popular architectures in common use today, and if OP's program is only meant to run on, say, modern x86 or modern ARM, which in this day and age is not at all unlikely, it'll work fine. – Charles Srstka Oct 09 '17 at 03:12
  • To unsolve your concerns, the code will only run on modern systems as @CharlesSrstka already mentioned. The purpose of the need of fixed struct width is, that I only have to copy a large incoming stream to the `struct uuu * ptr` and then read out single elements I need. – TeStUn.De Oct 09 '17 at 03:17
  • You mean *today's* modern systems, at least those of them with the same endianness as the ones you care about. – David Schwartz Oct 09 '17 at 03:21
  • @DavidSchwartz Most apps that people write are meant for a specific operating system/hardware combo. It might be a Windows app, or an iPhone app, or something similar. So portability isn't necessarily a requirement. – Charles Srstka Oct 09 '17 at 03:37
  • 1
    @DavidSchwartz With that said, when I'm reading a structure, I do tend to read the individual elements one at a time and run them through the API that the framework I'm using supplies to convert little/big to host endianness (f/e `CFSwapInt32LittleToHost()` on Apple systems). And I've been yelled at for recommending doing *that*, since if your app is for iPhone or Windows or some other little-endian-only architecture, you can't test it on big-endian, and "untested code is incorrect code." So someone's always gonna downvote. I just try to answer the question asked in the OP. :-/ – Charles Srstka Oct 09 '17 at 03:40
  • @CharlesSrstka Maybe your experience differs from mine, but my experience has absolutely been the opposite. Most code is not for some specific app but is to serve some function that might be required by any number of applications. Also, new versions of Windows and the iPhone are likely to come up. Architectures change. Making something non-portable should be a last resort when there's some clear justification for doing so. – David Schwartz Oct 09 '17 at 05:43
  • 1
    @CharlesSrstka not that I suppose it matters, but my comment was to try to ensure the poster understood why an `__attribute__` was required, and what the original problem had been, not directly as a criticism. No negative vote from me. – Tommy Oct 09 '17 at 11:22