MinGW: __attribute__((packed)) und alignment

#4481383
Lesenswert?

Hallo zusammen,

ich habe ein struct definiert mit:
1
__extension__ typedef struct 
2
{
3
    uint16_t val0: 10; 
4
    uint16_t val1: 10;
5
    uint8_t crc : 4; 
6
} __attribute__((packed)) Eedata_t;

und baue das Ganze unter MinGW64 (eine GCC-Ausprägung für Windows). 
Sizeof von Eedata_t liefert 5 - d.h. der Compiler mag das struct nicht 
packen, sondern richtet es an 16-Bit-Grenzen aus.

Gibt es eine Möglichkeit, dem Compiler beizubiegen, ohne Rücksicht auf 
Optimierungsverluste und nötigen Schiebeoperationen das Ganze auf 24 Bit 
zu packen oder muß ich in den sauren Apfel beißen und von Hand schieben?


Viele Grüße
W.T.
Moderator Persönliche Seite #4481455
Lesenswert?

Seltsam:
1
$ cat foo.c
2
#include <stdint.h>
3

4
__extension__ typedef struct 
5
{
6
    uint16_t val0: 10; 
7
    uint16_t val1: 10;
8
    uint8_t crc : 4; 
9
} __attribute__((packed)) Eedata_t;
10

11
Eedata_t foo;
12

13
int getval1(Eedata_t *p)
14
{
15
   return p->val1;
16
}
17
$ cc -O -S foo.c
18
$ cat foo.s
19
        .file   "foo.c"
20
        .text
21
        .globl  getval1
22
        .type   getval1, @function
23
getval1:
24
.LFB0:
25
        .cfi_startproc
26
        movzbl  1(%rdi), %edx
27
        shrb    $2, %dl
28
        movzbl  %dl, %edx
29
        movzbl  2(%rdi), %eax
30
        andl    $15, %eax
31
        salq    $6, %rax
32
        orl     %edx, %eax
33
        ret
34
        .cfi_endproc
35
.LFE0:
36
        .size   getval1, .-getval1
37
        .comm   foo,3,1
38
        .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
39
        .section        .note.GNU-stack,"",@progbits

Kann mir nicht vorstellen, dass sich ein MinGW32 anders verhält als
der Compiler hier unter Linux.
#4481563
Lesenswert?

OK, wir haben uns etwas gedoppelt:

Unter Clang habe ich auch 3 Bytes als Größe (sowohl bei Deinem als auch 
meinem Minimalbeispiel).

Bei Deinem Minimalbeispiel unter MinGW64:
1
  .file  "foo.c"
2
  .text
3
  .globl  getval1
4
  .def  getval1;  .scl  2;  .type  32;  .endef
5
  .seh_proc  getval1
6
getval1:
7
  .seh_endprologue
8
  movzbl  2(%rcx), %edx
9
  movzbl  3(%rcx), %eax
10
  andl  $3, %eax
11
  salq  $8, %rax
12
  orl  %edx, %eax
13
  ret
14
  .seh_endproc
15
  .comm  foo, 5, 0
16
  .ident  "GCC: (tdm64-1) 5.1.0"

Für mich ist X64/X86er-Asm kryptisch, aber auf den ersten Blick sieht 
das nach einem anderen Offset aus.
#4481740
Lesenswert?

Jörg W. schrieb:
> Johann L. schrieb:
>> Gibt es mit unsigned das gleiche Ergebnis?
>
> Bzw. unsigned char / unsigned short?

"unsigned" bringt noch eine neue Variante ins Spiel:
1
  .file  "foo.c"
2
  .text
3
  .globl  getval1
4
  .def  getval1;  .scl  2;  .type  32;  .endef
5
  .seh_proc  getval1
6
getval1:
7
  .seh_endprologue
8
  movzbl  1(%rcx), %eax
9
  shrb  $2, %al
10
  movzbl  %al, %edx
11
  movzbl  2(%rcx), %eax
12
  andl  $15, %eax
13
  salq  $6, %rax
14
  orl  %edx, %eax
15
  ret
16
  .seh_endproc
17
  .comm  foo, 4, 0
18
  .ident  "GCC: (tdm64-1) 5.1.0"

bzw. der "sizeof"-Operator liefert 4 zurück.
#4481885
Lesenswert?

Ich hab's produktiv mit Bitschieberei gelöst - auch wenn mir type 
punning über Bitfelder lieber ist (da wartbarer).

Es verbleibt also nur die Neugier, warum GCC 5.1.0 und Clang 
unterschiedlicher Meinung sind, was ihre Interpretation von "packed" 
angeht.

(Ich bitte von Vorschlägen à la "nimm eine andere GCC-Version" 
abzusehen. Diese Distribution mit MinGW64/TDM-GCC arbeitet hervorragend 
als MEX-Compiler mit Matlab zusammen - was andere Versionen leider 
(noch) nicht tun.)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren