2

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.

Nick
  • 9,962
  • 4
  • 42
  • 80
  • 2
    tcc and gcc are different compilers, using different syntax for extensions (like `__attribute__`). AFAIK tcc is no longer maintained, so why to use it anyway? – Eugene Sh. Feb 20 '15 at 20:55
  • I was curios if my code is portable and tried with tcc. It did compiled without a warning. However I need packed structs and according to tcc documentation it supports it. – Nick Feb 20 '15 at 21:02
  • just another 5 cents - above test works on clang – Nick Feb 20 '15 at 21:32

3 Answers3

2

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.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
1

I can confirm that at least with tcc 0.9.26 attribute((packed)) on struct members is not working. Using Windows-style packing pragmas works just fine:

    #if defined(__TINYC__)
    #pragma pack(1)
    #endif

    typedef struct {
            uint16_t ..
    } interrupt_gate_descriptor_t;

    #if defined(__TINYC__)
    #pragma pack(1)
    #endif
0

Seems to be error with TCC.

according many sources , including this one, http://wiki.osdev.org/TCC

this should work:

struct some_struct {
   unsigned char a __attribute__((packed));
   unsigned char b __attribute__((packed));
} __attribute__((packed));

... but it does not work.

Nick
  • 9,962
  • 4
  • 42
  • 80