Bit in memory

X86 machine, OS: Linux 2.6 RH. Here are my codes:

    #include "stdio.h"
    typedef struct ch_t
    {
        int c0:1;
        int c1:1;
        int c2:1;
        int c3:1;
        int c4:1;
        int c5:1;
        int c6:1;
        int c7:1;
    } ch;

    typedef union chh_u
    {
        char a;
        ch chat;
    } chh;
    int main(void)
    {
        chh uu;
        uu.a = 6;
        printf("\n%d", uu.chat.c0);
        printf("\n%d", uu.chat.c1);
        printf("\n%d", uu.chat.c2);
        printf("\n%d", uu.chat.c3);
        printf("\n%d", uu.chat.c4);
        printf("\n%d", uu.chat.c5);
        printf("\n%d", uu.chat.c6);
        printf("\n%d", uu.chat.c7);
        printf("\n%d\n", uu.a);
        return 0;
    }

      

As I expected, the output should be:

0 0 0 0 0 1 1 0 6

But the actual result was:

0 -1 -1 0 0 0 0 0 6

I can't figure out why the output is above. I think the 6-bit order is 0000 0110, and in memory, in my version, the bit order is also 0000 0110. But the result shows the difference.

Can someone explain this?

+3


source to share


4 answers


The relevant parts of the standard are 6.7.2 (5).

Each of the comma-separated sets denotes the same type , except that for bit-fields it is implementation-defined: the specifier int

denotes the same type as signed int

, or the same type as unsigned int

.

... this explains why you (can) get -1 instead of 1 for given bits. The other is 6.7.2.1 (10):

An implementation can allocate any address storage block large enough to store the bit field. If there is enough space left, the bit-field that immediately follows another bit-field in the structure should be packed into adjacent bits of the same block. If insufficient space remains, then whether a bit-field that does not fit fits into the next bits or overlaps adjacent ones is implementation-defined. The order in which the bit-fields are allocated within a device (from high order to low or low order) is implementation-defined. Storage address block alignment unspecified.

So this can go anyway too.

Addendum: Since there seems to be some confusion about this: calling a function with a variable argument list with bitfields is good if the function is expecting int

inside, for the same reasons that it's okay to say

char c = '\xff';
printf("%d\n", c); // will usually print 255 or -1

      

and it can give different results for the same reasons, because like a bitfield, a char

can be signed or unsigned depending on the implementation. I'll cite the relevant bits, with the irrelevant parts stripped out this time, because those rules are buried in the somewhat tediously legal parts of the C99 standard. They are found in 6.5.2.2 (6):



If the expression denoting the function being called is of a type that does not contain a prototype, integer actions are performed for each argument , and the type arguments are float

converted to double

. These are called default promotions. (...)

and 6.5.2.2 (7):

(...) The ellipsis notation in the function prototype declarator causes the argument type conversion to stop after the last declared parameter. By default, active declarations are executed when arguments are completed .

Targeted promotions are defined in 6.3.1.1; the corresponding bit is given in paragraphs 2 and 3:

2 For use int

or unsigned int

can be used the following:

  • (...)
  • Bit field type _Bool

    , int

    , signed int

    or unsigned int

    .

If it int

can represent all values ​​of the original type, the value is converted to a value int

; otherwise, it is converted to unsigned int

. (...)

3 Integer stocks retain their value, including the sign. (...)

So this happens:

  • Your compiler treats bitfields int

    as signed
  • This means that a 1-wide bitfield with its set of bits is -1; this, as they say, is only a sign, and it is installed.
  • On transition to, printf

    it is converted, keeping this value, toint

  • This int is printed printf

    according to the format string %d

    and gives you "-1".
  • Profit?
+4


source


Try to make values ​​in your bitfield unsigned

. This avoids the unexpected behavior you experience.



typedef struct ch_t {
    unsigned int c0:1;
    unsigned int c1:1;
    unsigned int c2:1;
    unsigned int c3:1;
    unsigned int c4:1;
    unsigned int c5:1;
    unsigned int c6:1;
    unsigned int c7:1;
} ch;

      

+1


source


This is where you create a variable signed int

[usually the int

default signed int

] bitfield

) and try to print the value using the format specifier %d

. Unfortunately this will not give you the correct value for single bit bit fields.

As @wintermute explains in his comment, when using bit variables directly in printf()

, they are counted signed integer

. OTOH, according to a rule, one bit signed integer

can be either 0

or -1

, and so in this case the representation will -1

.

Also, in your case, I assume you understand what c0

is LSB

and c7

will be MSB

, right?

The required bit must be removed before printing. Try something like below.

#include <stdio.h>
typedef struct ch_t
{
        int c0:1;
        int c1:1;
        int c2:1;
        int c3:1;
        int c4:1;
        int c5:1;
        int c6:1;
        int c7:1;
} ch;

typedef union chh_u
{
        char a;
        ch chat;
} chh;
int main(void)
{
        chh uu;
        uu.a = 6;
        printf("\n%d", (uu.chat.c0) && 0x01);
        printf("\n%d", (uu.chat.c1) && 0x01);
        printf("\n%d", (uu.chat.c2) && 0x01);
        printf("\n%d", (uu.chat.c3) && 0x01);
        printf("\n%d", (uu.chat.c4) && 0x01);
        printf("\n%d", (uu.chat.c5) && 0x01);
        printf("\n%d", (uu.chat.c6) && 0x01);
        printf("\n%d", (uu.chat.c7) && 0x01);
        printf("\n%d\n", uu.a);
        return 0;
}

      

Otherwise, use unsigned int

the datatype in your structure definition.

0


source


In struct ch_t

bit fields c0

.. c7

occupy the least significant 8 bits, both c0

as the lowest (2 ^ 0) and c7

as the highest (2 ^ 7). Set from highest to lowest, as if writing a binary number you have c7 c6 c5 c4 c3 c2 c1 c0

. The number 6 in 8 binary digits is 00000110

, therefore, means that c2

they c1

contain 1

bits, and the rest contain bits 0

. This matches the output you got where these fields were showing -1

.

The reason they show up as -1

instead 1

is because you used int

instead unsigned int

for your bitfields. This effectively gives you a 1 bit signed integer type which for 2 compliments can only contain 0 or -1.

0


source







All Articles