0

The below algorithm can output 99 0000

Would you please let me know how does this following line of code work?

*(long*)&(st->flag1) = 0;

The algorithm is:

#include <stdio.h>

struct SpecialFlags{
 int  id;
 char flag1;
 char flag2;
 char flag3;
 char flag4;
};


void ClearFlags( SpecialFlags *st )
{
  *(long*)&(st->flag1) = 0;
}

int main(void)
{
  SpecialFlags flags;
  flags.id =    99;

  flags.flag1 = 1;
  flags.flag2 = 2;
  flags.flag3 = 3;
  flags.flag4 = 4;
  ClearFlags( &flags );

  printf( "%d %d%d%d%d\n", flags.id, 
    flags.flag1, flags.flag2, 
    flags.flag3, flags.flag4 );
  return 0;
}
arheops
  • 15,544
  • 1
  • 21
  • 27
LAYMOONI
  • 13
  • 3
  • 11
    It drives the last nail into the undefined coffin. – Quentin Feb 21 '18 at 14:07
  • Read from right to left. Take the address (`&`) of `st->flag1`, cast it to a `long*`, and then dereference (`*`) that pointer. Whoever wrote that is using it as a terrible hack to set all four `flag`s to 0. – 0x5453 Feb 21 '18 at 14:09
  • @0x5453 `&` here takes the address of, not reference – NathanOliver Feb 21 '18 at 14:10
  • ...**if** `sizeof long` actually is 4... – DevSolar Feb 21 '18 at 14:12
  • `st` is a pointer of type `SpecialFlags`. `st->flag1` is the first flag in that struct. `&(st->flag1)` is the address of the first element of type char with size 1 byte. (long*)&(st->flag1) is a pointer of type long (size is usually 4) to the address of the first flag. `*(long*)&(st->flag1) = 0;` sets 4 bytes beginning with the address of flag1 to 0. Since each flag uses one of these 4 bytes, each flag is set to 0. – Thomas Sablik Feb 21 '18 at 14:15
  • @DevSolar That's platform-dependent, as is `sizeof(int)`. The only basic type with a size defined by the standard is `char`. – 3Dave Feb 21 '18 at 14:17
  • You should use `memset (st, 0, 4);` from `cstring` at this point. – Thomas Sablik Feb 21 '18 at 14:24
  • @DavidLively: That was what I was hinting at. If `long` is *not* `4` but e.g. `8`, this code will write beyond the bounds of the `struct`, invoking undefined behaviour. – DevSolar Feb 21 '18 at 14:26
  • @Thomas, did you mean `memset (st, 0, sizeof *st);`? I don't know where that `4` came from - we already know that `sizeof *st` is at least 4 more than `sizeof (int)`. – Toby Speight Feb 21 '18 at 15:25
  • 1
    @DevSolar I missed the `if` in your comment. – 3Dave Feb 21 '18 at 16:49
  • @TobySpeight: no, I meant `memset(&(st->flag1), 0, 4);`. This is the memory of the 4 flags. I don't want to change the memory of `st->id`. The 4 comes from 4 flags, each with size 1 byte. – Thomas Sablik Feb 22 '18 at 07:47

1 Answers1

0

In the Below structure

struct SpecialFlags{
        int  id;
        char flag1;
        char flag2;
        char flag3;
        char flag4;
};

        id       flag1     flag2     flag3      flag4
     -------------------------------------------------- 
     | 99      | 1(49)    | 2(50)   | 3(51)   |  4(52) |
     ---------------------------------------------------
   0x100     0x104       0x105     0x106      0x107   0x108 <--lets say starting address is 0x100

When ClearFlags() is called st points to beginning of the structure. And when you do *(long*)&(st->flag1) = 0; First address of st->flags1(char type) gets converted to long* type that means it will fetch 4 bytes at a time and finally * means value in that 4 bytes.

From above figure

  • (long*)&(st->flag1) => from 0x104 address till next 4 byte i.e till 0x108
  • *(long*)&(st->flag1) => what value is there in between 0x104 location to 0x108 location
  • *(long*)&(st->flag1) = 0 => what value is there in between 0x104 location to 0x108 location, will be overwritten with 0(zero)

After this statement your structure looks like

       id       flag1     flag2     flag3      flag4
     -------------------------------------------------- 
     | 99      | 0(48)    | 0(48)   | 0(48)   |  0(48) |
     ---------------------------------------------------
   0x100     0x104       0x105     0x106      0x107   0x108

Now when you prints flags.flag1, flags.flag2.. it prints 0.

Achal
  • 11,821
  • 2
  • 15
  • 37
  • There is a small mistake. The values are numbers and not chars. So 0 is 0 and not 48. If you want to set the flags to `'0'`, you need to assign `*(long*)&(st->flag1) = 48+256*(48+256*(48+256*48));` – Thomas Sablik Feb 22 '18 at 07:52