2

I have a text file that I have to read and parse. each line contains a HEX value in ASCII format. For example:

0100002c
0100002c
80000000
08000000
0a000000

After conversion to signed 32bit integer, I have to check the bits in the following fashion:

bit #31 => should result in decimal 0 or 1
bit #30 to 23 => should result in decimal 0 to 10
bit #22 to 0 => should result in a signed decimal number

I assign the raw int32 to the following struct/union (I only set the raw part):

typedef struct DATA{
    union {
        int32_t raw;
        struct {
            int32_t data:24;
            uint8_t operation:7;
            uint8_t binop:1;
        };
    } members;
} data_t;

Now the problem is, on a Linux machine and compiling with GCC (I tried 4.8 and 5.4) I get the correct results using the following function:

void vm_data_debug(data_t* const inst, int const num) {
    printf("DEBUG DATA #%d => "
                   " RAW: %-12d"
                   " BINCODE: %-1d"
                   "\tOPCODE: %-1d"
                   "\tDATA: %-10d", num, inst->members.raw,
           inst->members.binop, inst->members.operation , inst->members.data);

    printf("\tBITS: ");
    vm_data_print_raw_bits(sizeof inst->members.raw, &inst->members.raw);
}

And here is the result of the example ASCII on the top of the question on a Linux machine, fine and dandy!

DEBUG DATA #0 =>  RAW: 16777260     BINCODE: 0  OPCODE: 1   DATA: 44            BITS: 00000001000000000000000000101100
DEBUG DATA #1 =>  RAW: 16777260     BINCODE: 0  OPCODE: 1   DATA: 44            BITS: 00000001000000000000000000101100
DEBUG DATA #2 =>  RAW: -2147483648  BINCODE: 1  OPCODE: 0   DATA: 0             BITS: 10000000000000000000000000000000
DEBUG DATA #3 =>  RAW: 134217728    BINCODE: 0  OPCODE: 8   DATA: 0             BITS: 00001000000000000000000000000000
DEBUG DATA #4 =>  RAW: 167772160    BINCODE: 0  OPCODE: 10  DATA: 0             BITS: 00001010000000000000000000000000

Now, using the exact same code on a Windows machine (same machine that I run Linux on) I get a very different result (I have compiled with both MinGW and MSVC2015):

DEBUG DATA #0 =>  RAW: 16777260     BINCODE: 1   OPCODE: 77      DATA: 44                BITS: 00000001000000000000000000101100
DEBUG DATA #1 =>  RAW: 16777260     BINCODE: 1   OPCODE: 77      DATA: 44                BITS: 00000001000000000000000000101100
DEBUG DATA #2 =>  RAW: 2147483647   BINCODE: 1   OPCODE: 77      DATA: -1                BITS: 01111111111111111111111111111111
DEBUG DATA #3 =>  RAW: 134217728    BINCODE: 1   OPCODE: 77      DATA: 0                 BITS: 00001000000000000000000000000000
DEBUG DATA #4 =>  RAW: 167772160    BINCODE: 1   OPCODE: 77      DATA: 0                 BITS: 00001010000000000000000000000000

So the question is, where does this difference come from? What should I do to make it consistent between both Windows and Linux?

I have checked this question but it does not fix it for me, having the union members all signed or unsigned still does not work on Windows.

timrau
  • 22,578
  • 4
  • 51
  • 64
Dumbo
  • 13,555
  • 54
  • 184
  • 288
  • Possible duplicate of [Why do bit fields in C need to be defined of type unsigned int or signed int](https://stackoverflow.com/questions/23987376/why-do-bit-fields-in-c-need-to-be-defined-of-type-unsigned-int-or-signed-int) – Stargateur Jun 03 '17 at 09:53
  • @Stargateur Making the fields all unsigned or all signed still results in the inconsistency between platforms. – Dumbo Jun 03 '17 at 09:57
  • Have you try to convert them to `signed int` (all your type in your struct/union) ? Just a guess, your question is very hard. I think this is implementation defined but maybe there are a solution. But this is not in my knowledge. – Stargateur Jun 03 '17 at 09:57
  • Did you check `sizeof inst.members` to ensure it's exactly 32 bits on both platforms? –  Jun 03 '17 at 09:59
  • @ChronoKitsune hmm that reads 8!!!! whats going on? – Dumbo Jun 03 '17 at 10:02
  • @SaeidYazdani http://rextester.com/EIOSG44642, use the same type size like I said. – Stargateur Jun 03 '17 at 10:13
  • I'm not sure what's happening, except perhaps that the `uint8_t` members are causing a problem. It appears to work fine if `uint8_t` is changed to `unsigned int` as @Stargateur mentioned. I'm not certain what's occurring, but clearly you should be following the standard. When I turn on warnings on MinGW, I get compilation warnings like `'inst.members.binop' is used uninitialized` with `uint8_t`, but they stop when `unsigned int` is used. –  Jun 03 '17 at 10:45
  • 3
    There is no requirement from the standard bitfield structs have an identical layout. And none other types than `int`, `unsign` or `_Bool` can be used at all. Use proper marshalling of the fields with shifts/masking. Anything else is doomed by design. As a sidenote: names ending with `_t` are reserved by POSIX. Your code is invalid on such systems (like Linux). – too honest for this site Jun 03 '17 at 11:00
  • 3
    Almost everything about bit-fields is implementation defined. That means that the organization of the bit-fields can be handled differently by different compilers — and you've demonstrated that these compilers _do_ do it differently. Both are correct. Using bit fields is not portable, so don't use them in portable code. – Jonathan Leffler Jun 03 '17 at 11:28

0 Answers0