2

Hanging on geeksforgeeks about bitfields, found this example:

#include <stdio.h>

struct test {
    unsigned int x;
    long int y : 33;
    unsigned int z;
};

int main() {
    struct test t;
    unsigned int *ptr1 = &t.x;
    unsigned int *ptr2 = &t.z;
    printf("%d", ptr2 - ptr1);
    return 0;
}

As result, output is 4. But why? x occupies 4 bytes, y - 8, and z - 4. Difference in addresses x and z must be 8?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
artsin
  • 1,434
  • 2
  • 13
  • 29
  • 3
    The difference between two pointers is not counted in bytes, but in whatever type the pointers point to. Moreover, `type` is aligned to the alignment of the most aligned member (probably `long int`), and `&test.x == &test`, so if `sizeof(unsigned) != sizeof(long int)`, there is an alignment gap (padding) between `test.x` and `test.y`, provided the implementation even accepts bitfields of type `long int`. – EOF Feb 15 '16 at 10:30
  • 3
    I keep hearing about this "geekforgeeks" in every post that contains awful, poorly-specified behavior, nonsense code. I really think you should avoid that site, it doesn't quite seem like they know what they are talking about there. – Lundin Feb 15 '16 at 10:42
  • Lundin: Maybe I can agree, I've found it just couple of days ago... But anyway, this tricky "spherical horse in a vacuum" example, struggled me:) – artsin Feb 15 '16 at 10:46
  • @artsin The correct term is spherical cow. – ElderBug Feb 15 '16 at 10:48
  • @artsin The code was written by a spherical horse? The only thing to learn from this code is that bit-fields should be avoided entirely. [See this](http://stackoverflow.com/questions/6043483/why-bit-endianness-is-an-issue-in-bitfields/6044223#6044223) for example. – Lundin Feb 15 '16 at 10:50
  • It think it speaks for itself that [this post](http://www.geeksforgeeks.org/scansets-in-c/) on geeksforgeeks for example, warns about using gets, and then uses various variations of `scanf("%s")` without specifying maximum field width. I don't think content is reviewed too well over there. – user694733 Feb 15 '16 at 11:10
  • 1
    @Lundin: I don't see how one'd conclude that "bit-fields should be avoided entirely" from that. Most problems with bit-fields arise from bizarre misguided attempts to force the compiler to allocate bit-fields in accordance with some external layout specification. True, bit-fields don't work well for that purpose. But why would anyone even try to use them for that purpose? This is not what bit-fields are for. – AnT stands with Russia Feb 16 '16 at 22:57
  • @AnT That's the problem, _everyone_ who use them use them to map a memory specific layout: hardware registers, data packets etc. _Nobody_ uses them for what they could actually be safely used as, like a collection of boolean flags, storing chunks of small data etc. Bit-fields is a 100% superfluous feature anyway, there is never a reason to use them anywhere, even in the very rare cases when they are safe to use. – Lundin Feb 17 '16 at 07:16
  • @Lundin: I believe your experience is rather lopsided. Mine is quite different: I see a lot of people use bit-fields correctly, in accordance with their native purpose, i.e. to save memory. Why you call that native purpose "superfluous" is completely unclear to me. "Never a reason", really? There's never a reason to save memory these days? – AnT stands with Russia Feb 17 '16 at 07:33
  • Hey, guys, I have one notice for this conversation. I am fully agreed with statements, that usage of bitfields with such way is bad idea. But I think, it is useful, due to a) It is necessary to know, that you DO NOT NEED to do, and b) such kind of questions I think happens on interviews (for which I want to prepare by the way...) Of course, IMHO – artsin Feb 17 '16 at 10:25

1 Answers1

7

This code has no determinable behavior. It is impossible to predict any outcome of it without a very specific compiler in mind.

It contains the following implementation-defined behavior (quotes from Annex J of the standard):

— Whether a ‘‘plain’’ int bit-field is treated as a signed int bit-field or as an unsigned int bit-field (6.7.2, 6.7.2.1).

— Allowable bit-field types other than _Bool, signed int, and unsigned int (6.7.2.1).

— Whether a bit-field can straddle a storage-unit boundary (6.7.2.1).

— The order of allocation of bit-fields within a unit (6.7.2.1).

— The alignment of non-bit-field members of structures (6.7.2.1). This should present no problem unless binary data written by one implementation is read by another.

The second remark also implies that the compiler must have a non-standard extension.

On top of that, the code also depends on endianess and you cannot know which bits in the bit-field that are the MSB and LSB.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    More relevant: C11 draft standard `6.5.6 Additive operators, Section 9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object;[...]`. Though `6.5.8 Relational operators, Section 5 [...] If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure[...]` makes it *likely* no real implementation is going to fail this code. – EOF Feb 15 '16 at 10:53
  • Also, `sizeof(int)` and `sizeof(long)` are also implementation defined. We can see here this code was compiled with a 64-bit non-MSVC compiler because `sizeof(long)` is 8. With MSVC or 32-bit compilers, `sizeof(long)` is 4. – ElderBug Feb 15 '16 at 10:57
  • @EOF Yes, I am sure one could write a full essay about how this code could/will go wrong. Just don't write such nonsense code and there will be no problems. – Lundin Feb 15 '16 at 10:57