0

Consider the following snippet from code running in the Linux kernel:

    char *d;
    u32 mask, step, val;
    ...
    /* d is initialized with valid pointer pointing at buffer,
and mask, step and val are initialized to some sane values as well. */
    ...
    val = (*d & mask) >> step;

As you see only d is of char * type, the rest are unsigned integers. I know that C performs type conversions automatically when values of differing types participate in expressions, in this case bit-wise operation. So, I'm assuming it is guaranteed that *d will be promoted to uint32_t as well?

If this assumption is correct, my 2nd question would be about the byte-order of 4 bytes located at memory pointed by d. I think it has to be whatever byte-order the host implements, or if it's networking, then strictly big-endian.

Mark
  • 6,052
  • 8
  • 61
  • 129

1 Answers1

3

Because d has type char * it reads a single byte at the address pointed to by d. So the expression *d has type char which has the value of the byte pointed to by d. Endianness doesn't matter here because only a single byte is read from d.

In the larger expression *d & mask, the value *d which has type char is converted to uint32_t for use in the expression.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • thanks for comments. So after promotion to `int` and later on conversion ti `u32` (or `uint32_t`), the endiannes matters. Will it be the host endiannes? I updated the question, because I see the same in linux kernel, where is processes network socket buffers, so whatever has arrived from the network is stored in `skb`, and it is in `network` byte-order. – Mark Jun 13 '18 at 17:49
  • How did you conclude the endianess matter? In your posted code the value of `val` *does not depend* on the endianness of the machine – Eugene Sh. Jun 13 '18 at 17:50
  • 1
    @Mark The endiness matters only after you've read each byte individually and have to interpret them. `*d` only pulls one byte from the buffer, not 4. – dbush Jun 13 '18 at 17:50
  • [This is](http://port70.net/~nsz/c/c11/n1570.html#6.3.1.8) (and [this](http://port70.net/~nsz/c/c11/n1570.html#6.3.1.3))how it is converted. Note the lack of any endianess reference. – Eugene Sh. Jun 13 '18 at 17:55
  • 1
    @Mark `*d` is one byte, holding a value from -128 to 127. When it is converted, it will still have a value in that range. Converting `*d` to a larger type doesn't automatically pull the next 3 bytes after the one `d` points to. – dbush Jun 13 '18 at 17:57
  • @dbush, so it means that `printf("%08x", *d)` will produce the same result on any byte-order machines? – Mark Jun 13 '18 at 19:16
  • 2
    @Mark Correct. It's only a single byte, so endianness does not come into play. – dbush Jun 13 '18 at 19:18
  • 1
    CPU registers do not have endianness. Once a byte has been read from memory into a register, any binary bit-masking (and-ing) and shifting operate on the arithmetic binary value of the register as a whole. – David R Tribble Jun 13 '18 at 20:40
  • @DavidRTribble is it always guaranteed that operands (in this case bitwise operations) will be in CPU registers? – Mark Jun 15 '18 at 15:47
  • @Mark As far as the C language is concerned no, although in practice it will probably be the case. – dbush Jun 15 '18 at 16:27
  • 1
    @Mark, It's hard to conceive of an existing CPU architecture that does not load its registers with expression operands at some point. But my point is that integer operands do not have an endianness within evaluated expressions, just binary values of some bit width. In other words, `1 << 12` will be the same value regardless of CPU endianness. Endianness is simply not relevant to integer expression evaluation. – David R Tribble Jun 18 '18 at 15:00