Nick Nick - 1 year ago 38
C Question

packed structs in tcc

I am trying to do packed struct in tcc C compiller.
Code is as follows and __attribute __ tag should be supported:

#include <stdio.h>
#include <stdint.h>

typedef struct _test_t{
char c;
uint16_t i;
char d;
} __attribute__((__packed__)) test_t;

int main(){
test_t x;
x.c = 0xCC;
x.i = 0xAABB;
x.d = 0xDD;

const char *s = (const char *) & x;

unsigned i;
for(i = 0; i < sizeof(x); i++)
printf("%3u %x\n", i, 0xFF & s[i]);

return 0;
}


It works in gcc, but not work on tcc.
I also tried __attribute __((packed)) and few other tests - none works.

Answer Source

As you already found the __attribute__ extension applies only to struct's members, so each of them should have it applied individually. Here is your code with minor adaptations, that compiles with tcc 0.9.26 and then runs with correct output:

typedef struct {
    char             c __attribute__((packed));
    unsigned short   i __attribute__((packed));
    char             d __attribute__((packed));
} test_t;

int main(void)
{
    test_t x;

    printf("%zu\n", sizeof(test_t));

    x.c = 0xCC;
    x.i = 0xAABB;
    x.d = 0xDD;

    const char *s = (const char *) &x;

    unsigned i;
    for (i = 0; i < sizeof(x); i++)
        printf("%3u %x\n", i, 0xFF & s[i]);

    return 0;
}

Result:

4
  0 cc
  1 bb
  2 aa
  3 dd

There is one catch here. As you may already spotted there are no headers. The correctly written code should have:

#include <stdio.h>
#include <stdint.h> // then replace unsigned short with uint16_t

However, with headers the __attribute__ is no longer working. I am not sure if that always happen, but on my system (CentOS 6) it does exactly in that way.

As I found the explanation lies in internal sys/cdefs.h header, that contains:

/* GCC has various useful declarations that can be made with the
   `__attribute__' syntax.  All of the ways we use this do fine if
   they are omitted for compilers that don't understand it. */
#if !defined __GNUC__ || __GNUC__ < 2
# define __attribute__(xyz) /* Ignore */
#endif

so the __attribute__ function-like macro is "washed-up" for tcc, as it does not define __GNUC__ macro. It seems to be some incoherence between tcc developers and standard library (here glibc) writers.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download