Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrectly initialized bit fields in structure #1262

Open
negge opened this issue Mar 29, 2024 · 5 comments
Open

Incorrectly initialized bit fields in structure #1262

negge opened this issue Mar 29, 2024 · 5 comments
Labels
bug C C compiler

Comments

@negge
Copy link

negge commented Mar 29, 2024

Creating a struct that uses packed bit fields does not match the C specification with differently sized types. For example:

#include <stdio.h>

typedef struct key key;

struct key {
  struct {
    unsigned char type : 2;
    unsigned short row : 12;
  };
};

#define MAX_ROW (4*60*60/8)

typedef enum {
  STEP = 0,
  SMOOTH = 1,
  LINEAR = 2,
  RAMP = 3,
} simp_type;

static char *TYPE_STR[] = {
  "STEP", "SMOOTH", "LINEAR", "RAMP",
};

key keys[] = {
   { .row = MAX_ROW, .type = RAMP },
};

int main() {
  printf("sizeof(key) = %i\r\n", sizeof(key));
  printf("keys[0] = { .row = %3i, .type = %s }\r\n",
   keys[0].row, TYPE_STR[keys[0].type]);
  printf("%04x", *(int *)&keys[0]);
}

when built with Version 2.0 beta Mar 1 2024 01:51:55 (64-bit) prints the output:

sizeof(key) = 4
keys[0] = { .row = 1800, .type = RAMP }
7080003

However building with gcc -m32 keys.c -o keys gives the following output:

$ ./keys
sizeof(key) = 2
keys[0] = { .row = 1800, .type = RAMP }
1c23
@jmalak
Copy link
Member

jmalak commented Mar 29, 2024

For which standard?
Do you thing that gcc in default mode follow standard?
Anyway your key structure is invalid by C90 standard.
Both compilers are using some extension and default pack size which is not same.
What command line you use for OW compiler and what target.

Anyway OW compiler process your structure following way

unsigned char type : 2;  // allocate byte member and use 2 bits

unsigned short row : 12; // different type therefore cannot continue previous member, 
                            // need allocate 2-bytes member and need align it on 2-byte boundary

Therefore size is 4-bytes.

What is done by gcc is completely different then C standard.
It looks like gcc pack all bits into one member and ignore defined type alignment.

@jmalak
Copy link
Member

jmalak commented Mar 29, 2024

If you want bits be packed by OW as by gcc then use same type as

struct key {
struct {
unsigned short type : 2;
unsigned short row : 12;
};
};

@negge
Copy link
Author

negge commented Mar 30, 2024

If you want bits be packed by OW as by gcc then use same type as

struct key { struct { unsigned short type : 2; unsigned short row : 12; }; };

Thank you, I modified the example for both fields as short and the bit layout is now correct. However, I am still seeing strange things in the initializer. Code is now:

#include <stdio.h>

typedef struct key key;

struct key {
  struct {
    unsigned short type : 2;
    unsigned short row : 12;
  };
};

#define MAX_ROW (4*60*60/8)

typedef enum {
  STEP = 0,
  SMOOTH = 1,
  LINEAR = 2,
  RAMP = 3,
} simp_type;

static char *TYPE_STR[] = {
  "STEP", "SMOOTH", "LINEAR", "RAMP",
};

key keys[] = {
   { .row = MAX_ROW, .type = RAMP },
};

int main() {
  printf("sizeof(key) = %i\r\n", sizeof(key));
  printf("keys[0] = { .row = %3i, .type = %s }\r\n",
   keys[0].row, TYPE_STR[keys[0].type]);
  printf("%04x\r\n", *(int *)&keys[0]);
  /* set values again */
  keys[0].row = MAX_ROW;
  keys[0].type = RAMP;
  printf("keys[0] = { .row = %3i, .type = %s }\r\n",
   keys[0].row, TYPE_STR[keys[0].type]);
  printf("%04x", *(int *)&keys[0]);
}

Now prints out:

sizeof(key) = 2
keys[0] = { .row =   0, .type = RAMP }
0003
keys[0] = { .row = 1800, .type = RAMP }
1c23

But gcc -m32 keys.c -o keys gives the output:

$ ./keys
sizeof(key) = 2
keys[0] = { .row = 1800, .type = RAMP }
1c23
keys[0] = { .row = 1800, .type = RAMP }
1c23

@jmalak
Copy link
Member

jmalak commented Mar 30, 2024

It looks like bug in static initialization of bit fields.

@jmalak jmalak added bug C C compiler labels Mar 30, 2024
@jmalak jmalak changed the title Incorrect struct layout of packed bit fields Incorrectly initialized bit fields in structure Mar 30, 2024
@jmalak
Copy link
Member

jmalak commented May 3, 2024

#1283
#1274

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug C C compiler
Projects
None yet
Development

No branches or pull requests

2 participants