Why is assigning a value to a bit field not giving the same value back?












96















I saw the below code in this Quora post:



#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabledn"); // --> we think this to be printed
else
printf("Is disabled !!n");
}


In both C & C++, the output of the code is unexpected,




Is disabled !!




Though the "sign bit" related explanation is given in that post, I am unable to understand, how it is possible that we set something and then it doesn't reflect as it is.



Can someone give a more elaborate explanation?





Note: Both the tags c & c++ are required, because their standards slightly differ for describing the bit-fields. See answers for C specification and C++ specification.










share|improve this question




















  • 44





    Since the bitfield is declared as int i think it only can hold the values 0 and -1.

    – Osiris
    Dec 19 '18 at 14:45






  • 5





    just think of it how int stores -1. All bits are set to 1. Hence, if you only have one bit it clearly has to be -1. So 1 and -1 in the 1 bit int are the same. Change the check to 'if (s.enabled != 0)' and it works. Because 0 it can't be.

    – Jürgen
    Dec 19 '18 at 15:09






  • 2





    It is true that these rules are the same in C and C++. But according to the tag usage policies, we should only tag this as C and refrain from cross-tagging when not needed. I'll remove the C++ part, it should not affect any posted answers.

    – Lundin
    Dec 19 '18 at 16:06






  • 7





    Have you tried changing it to struct mystruct { unsigned int enabled:1; };?

    – ChatterOne
    Dec 19 '18 at 16:08






  • 3





    Kindly read the C and C++ tag policies, particularly the part regarding cross-tagging C and C++ both, established through community consensus here. I'm not going into some rollback war, but this question is incorrectly tagged C++. Even if the languages happen to have some slight difference because of various TC, then make a separate question about the difference between C and C++.

    – Lundin
    Dec 20 '18 at 8:04
















96















I saw the below code in this Quora post:



#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabledn"); // --> we think this to be printed
else
printf("Is disabled !!n");
}


In both C & C++, the output of the code is unexpected,




Is disabled !!




Though the "sign bit" related explanation is given in that post, I am unable to understand, how it is possible that we set something and then it doesn't reflect as it is.



Can someone give a more elaborate explanation?





Note: Both the tags c & c++ are required, because their standards slightly differ for describing the bit-fields. See answers for C specification and C++ specification.










share|improve this question




















  • 44





    Since the bitfield is declared as int i think it only can hold the values 0 and -1.

    – Osiris
    Dec 19 '18 at 14:45






  • 5





    just think of it how int stores -1. All bits are set to 1. Hence, if you only have one bit it clearly has to be -1. So 1 and -1 in the 1 bit int are the same. Change the check to 'if (s.enabled != 0)' and it works. Because 0 it can't be.

    – Jürgen
    Dec 19 '18 at 15:09






  • 2





    It is true that these rules are the same in C and C++. But according to the tag usage policies, we should only tag this as C and refrain from cross-tagging when not needed. I'll remove the C++ part, it should not affect any posted answers.

    – Lundin
    Dec 19 '18 at 16:06






  • 7





    Have you tried changing it to struct mystruct { unsigned int enabled:1; };?

    – ChatterOne
    Dec 19 '18 at 16:08






  • 3





    Kindly read the C and C++ tag policies, particularly the part regarding cross-tagging C and C++ both, established through community consensus here. I'm not going into some rollback war, but this question is incorrectly tagged C++. Even if the languages happen to have some slight difference because of various TC, then make a separate question about the difference between C and C++.

    – Lundin
    Dec 20 '18 at 8:04














96












96








96


14






I saw the below code in this Quora post:



#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabledn"); // --> we think this to be printed
else
printf("Is disabled !!n");
}


In both C & C++, the output of the code is unexpected,




Is disabled !!




Though the "sign bit" related explanation is given in that post, I am unable to understand, how it is possible that we set something and then it doesn't reflect as it is.



Can someone give a more elaborate explanation?





Note: Both the tags c & c++ are required, because their standards slightly differ for describing the bit-fields. See answers for C specification and C++ specification.










share|improve this question
















I saw the below code in this Quora post:



#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabledn"); // --> we think this to be printed
else
printf("Is disabled !!n");
}


In both C & C++, the output of the code is unexpected,




Is disabled !!




Though the "sign bit" related explanation is given in that post, I am unable to understand, how it is possible that we set something and then it doesn't reflect as it is.



Can someone give a more elaborate explanation?





Note: Both the tags c & c++ are required, because their standards slightly differ for describing the bit-fields. See answers for C specification and C++ specification.







c++ c bit-fields signed-integer implementation-defined-behavior






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 18 at 6:12







iammilind

















asked Dec 19 '18 at 14:40









iammilindiammilind

44.7k20125254




44.7k20125254








  • 44





    Since the bitfield is declared as int i think it only can hold the values 0 and -1.

    – Osiris
    Dec 19 '18 at 14:45






  • 5





    just think of it how int stores -1. All bits are set to 1. Hence, if you only have one bit it clearly has to be -1. So 1 and -1 in the 1 bit int are the same. Change the check to 'if (s.enabled != 0)' and it works. Because 0 it can't be.

    – Jürgen
    Dec 19 '18 at 15:09






  • 2





    It is true that these rules are the same in C and C++. But according to the tag usage policies, we should only tag this as C and refrain from cross-tagging when not needed. I'll remove the C++ part, it should not affect any posted answers.

    – Lundin
    Dec 19 '18 at 16:06






  • 7





    Have you tried changing it to struct mystruct { unsigned int enabled:1; };?

    – ChatterOne
    Dec 19 '18 at 16:08






  • 3





    Kindly read the C and C++ tag policies, particularly the part regarding cross-tagging C and C++ both, established through community consensus here. I'm not going into some rollback war, but this question is incorrectly tagged C++. Even if the languages happen to have some slight difference because of various TC, then make a separate question about the difference between C and C++.

    – Lundin
    Dec 20 '18 at 8:04














  • 44





    Since the bitfield is declared as int i think it only can hold the values 0 and -1.

    – Osiris
    Dec 19 '18 at 14:45






  • 5





    just think of it how int stores -1. All bits are set to 1. Hence, if you only have one bit it clearly has to be -1. So 1 and -1 in the 1 bit int are the same. Change the check to 'if (s.enabled != 0)' and it works. Because 0 it can't be.

    – Jürgen
    Dec 19 '18 at 15:09






  • 2





    It is true that these rules are the same in C and C++. But according to the tag usage policies, we should only tag this as C and refrain from cross-tagging when not needed. I'll remove the C++ part, it should not affect any posted answers.

    – Lundin
    Dec 19 '18 at 16:06






  • 7





    Have you tried changing it to struct mystruct { unsigned int enabled:1; };?

    – ChatterOne
    Dec 19 '18 at 16:08






  • 3





    Kindly read the C and C++ tag policies, particularly the part regarding cross-tagging C and C++ both, established through community consensus here. I'm not going into some rollback war, but this question is incorrectly tagged C++. Even if the languages happen to have some slight difference because of various TC, then make a separate question about the difference between C and C++.

    – Lundin
    Dec 20 '18 at 8:04








44




44





Since the bitfield is declared as int i think it only can hold the values 0 and -1.

– Osiris
Dec 19 '18 at 14:45





Since the bitfield is declared as int i think it only can hold the values 0 and -1.

– Osiris
Dec 19 '18 at 14:45




5




5





just think of it how int stores -1. All bits are set to 1. Hence, if you only have one bit it clearly has to be -1. So 1 and -1 in the 1 bit int are the same. Change the check to 'if (s.enabled != 0)' and it works. Because 0 it can't be.

– Jürgen
Dec 19 '18 at 15:09





just think of it how int stores -1. All bits are set to 1. Hence, if you only have one bit it clearly has to be -1. So 1 and -1 in the 1 bit int are the same. Change the check to 'if (s.enabled != 0)' and it works. Because 0 it can't be.

– Jürgen
Dec 19 '18 at 15:09




2




2





It is true that these rules are the same in C and C++. But according to the tag usage policies, we should only tag this as C and refrain from cross-tagging when not needed. I'll remove the C++ part, it should not affect any posted answers.

– Lundin
Dec 19 '18 at 16:06





It is true that these rules are the same in C and C++. But according to the tag usage policies, we should only tag this as C and refrain from cross-tagging when not needed. I'll remove the C++ part, it should not affect any posted answers.

– Lundin
Dec 19 '18 at 16:06




7




7





Have you tried changing it to struct mystruct { unsigned int enabled:1; };?

– ChatterOne
Dec 19 '18 at 16:08





Have you tried changing it to struct mystruct { unsigned int enabled:1; };?

– ChatterOne
Dec 19 '18 at 16:08




3




3





Kindly read the C and C++ tag policies, particularly the part regarding cross-tagging C and C++ both, established through community consensus here. I'm not going into some rollback war, but this question is incorrectly tagged C++. Even if the languages happen to have some slight difference because of various TC, then make a separate question about the difference between C and C++.

– Lundin
Dec 20 '18 at 8:04





Kindly read the C and C++ tag policies, particularly the part regarding cross-tagging C and C++ both, established through community consensus here. I'm not going into some rollback war, but this question is incorrectly tagged C++. Even if the languages happen to have some slight difference because of various TC, then make a separate question about the difference between C and C++.

– Lundin
Dec 20 '18 at 8:04












6 Answers
6






active

oldest

votes


















77














Bit-fields are incredibly poorly defined by the standard. Given this code struct mystruct {int enabled:1;};, then we don't know:




  • How much space this occupies - if there are padding bits/bytes and where they are located in memory.

  • Where the bit is located in memory. Not defined and also depends on endianess.

  • Whether an int:n bitfield is to be regarded as signed or unsigned.


Regarding the last part, C17 6.7.2.1/10 says:




A bit-field is interpreted as having a signed or unsigned integer type consisting of the
specified number of bits 125)




Non-normative note explaining the above:




125) As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int,
then it is implementation-defined whether the bit-field is signed or unsigned.




In case the bitfield is to be regarded as signed int and you make a bit of size 1, then there is no room for data, only for the sign bit. This is the reason why your program might give weird results on some compilers.



Good practice:




  • Never use bit-fields for any purpose.

  • Avoid using signed int type for any form of bit manipulation.






share|improve this answer





















  • 4





    At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

    – Michael
    Dec 19 '18 at 19:38






  • 2





    @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

    – Michael
    Dec 20 '18 at 8:25








  • 3





    @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

    – Andrew Henle
    Dec 20 '18 at 10:56








  • 2





    @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

    – mtraceur
    Dec 20 '18 at 22:41






  • 2





    @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

    – mtraceur
    Dec 20 '18 at 23:20





















57















I am unable to understand, how is it possible that we set something and then it doesn't show up as it is.




Are you asking why it compiles vs. gives you an error?



Yes, it should ideally give you an error. And it does, if you use your compiler's warnings. In GCC, with -Werror -Wall -pedantic:



main.cpp: In function 'int main()':
main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
changes value from '1' to '-1' [-Werror=overflow]
s.enabled = 1;
^


The reasoning for why this is left up to being implementation-defined vs. an error may have more to do with historical usages, where requiring a cast would mean breaking old code. The authors of the standard may believe warnings were enough to pick up the slack for those concerned.



To throw in some prescriptivism, I'll echo @Lundin's statement: "Never use bit-fields for any purpose." If you have the kind of good reasons to get low-level and specific about your memory layout details that would get you to thinking you needed bitfields in the first place, the other associated requirements you almost certainly have will run up against their underspecification.



(TL;DR - If you're sophisticated enough to legitimately "need" bit-fields, they're not well-defined enough to serve you.)






share|improve this answer





















  • 14





    The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

    – Lundin
    Dec 19 '18 at 15:00








  • 8





    There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

    – John Bollinger
    Dec 19 '18 at 15:20






  • 5





    @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

    – Lundin
    Dec 19 '18 at 15:26








  • 1





    @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

    – HostileFork
    Dec 19 '18 at 15:29






  • 1





    This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

    – Leushenko
    Dec 19 '18 at 16:00



















22














This is implementation defined behavior. I am making the assumption that the machines you are running this on use twos-compliment signed integers and treat int in this case as a signed integer to explain why you don't enter if true part of the if statement.



struct mystruct { int enabled:1; };


declares enable as a 1 bit bit-field. Since it is signed, the valid values are -1 and 0. Setting the field to 1 overflows that bit going back to -1 (this is undefined behavior)



Essentially when dealing with a signed bit-field the max value is 2^(bits - 1) - 1 which is 0 in this case.






share|improve this answer


























  • "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

    – Lundin
    Dec 19 '18 at 14:56








  • 5





    @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

    – NathanOliver
    Dec 19 '18 at 15:00






  • 1





    The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

    – Lundin
    Dec 19 '18 at 15:03






  • 1





    @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

    – NathanOliver
    Dec 19 '18 at 15:08








  • 1





    @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

    – John Bollinger
    Dec 19 '18 at 15:08





















10














You could think of it as that in the 2's complement system, the left-most bit is the sign bit. Any signed integer with the left-most bit set is thus a negative value.



If you have a 1-bit signed integer, it has only the sign bit. So assigning 1 to that single bit can only set the sign bit. So, when reading it back, the value is interpreted as negative and so is -1.



The values a 1 bit signed integer can hold is -2^(n-1)= -2^(1-1)= -2^0= -1 and 2^n-1= 2^1-1=0






share|improve this answer































    8














    As per the C++ standard n4713, a very similar code snippet is provided. The type used is BOOL (custom), but it can apply to any type.




    12.2.4



    4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold
    all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field
    shall compare equal
    .
    [ Example:



    enum BOOL { FALSE=0, TRUE=1 };
    struct A {
    BOOL b:1;
    };
    A a;
    void f() {
    a.b = TRUE;
    if (a.b == TRUE) // yields true
    { /* ... */ }
    }


    — end example ]






    At 1st glance, the bold part appears open for interpretation. However, the correct intent becomes clear when the enum BOOL is derived from the int.



    enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
    struct mystruct { BOOL enabled:1; };
    int main()
    {
    struct mystruct s;
    s.enabled = TRUE;
    if(s.enabled == TRUE)
    printf("Is enabledn"); // --> we think this to be printed
    else
    printf("Is disabled !!n");
    }


    With above code it gives a warning without -Wall -pedantic:




    warning: ‘mystruct::enabled’ is too small to hold all values of ‘enum BOOL’
    struct mystruct { BOOL enabled:1; };




    The output is:




    Is disabled !! (when using enum BOOL : int)




    If enum BOOL : int is made simple enum BOOL, then the output is as the above standard pasage specifies:




    Is enabled (when using enum BOOL)






    Hence, it can be concluded, also as few other answers have, that int type is not big enough to store value "1" in just a single bit bit-field.






    share|improve this answer

































      1














      There is nothing wrong with your understanding of bitfields that I can see. What I see is that you redefined mystruct first as struct mystruct { int enabled:1; } and then as struct mystruct s;. What you should have coded was:



      #include <stdio.h>

      struct mystruct { int enabled:1; };
      int main()
      {
      mystruct s; <-- Get rid of "struct" type declaration
      s.enabled = 1;
      if(s.enabled == 1)
      printf("Is enabledn"); // --> we think this to be printed
      else
      printf("Is disabled !!n");
      }





      share|improve this answer























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53853540%2fwhy-is-assigning-a-value-to-a-bit-field-not-giving-the-same-value-back%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        77














        Bit-fields are incredibly poorly defined by the standard. Given this code struct mystruct {int enabled:1;};, then we don't know:




        • How much space this occupies - if there are padding bits/bytes and where they are located in memory.

        • Where the bit is located in memory. Not defined and also depends on endianess.

        • Whether an int:n bitfield is to be regarded as signed or unsigned.


        Regarding the last part, C17 6.7.2.1/10 says:




        A bit-field is interpreted as having a signed or unsigned integer type consisting of the
        specified number of bits 125)




        Non-normative note explaining the above:




        125) As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int,
        then it is implementation-defined whether the bit-field is signed or unsigned.




        In case the bitfield is to be regarded as signed int and you make a bit of size 1, then there is no room for data, only for the sign bit. This is the reason why your program might give weird results on some compilers.



        Good practice:




        • Never use bit-fields for any purpose.

        • Avoid using signed int type for any form of bit manipulation.






        share|improve this answer





















        • 4





          At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

          – Michael
          Dec 19 '18 at 19:38






        • 2





          @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

          – Michael
          Dec 20 '18 at 8:25








        • 3





          @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

          – Andrew Henle
          Dec 20 '18 at 10:56








        • 2





          @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

          – mtraceur
          Dec 20 '18 at 22:41






        • 2





          @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

          – mtraceur
          Dec 20 '18 at 23:20


















        77














        Bit-fields are incredibly poorly defined by the standard. Given this code struct mystruct {int enabled:1;};, then we don't know:




        • How much space this occupies - if there are padding bits/bytes and where they are located in memory.

        • Where the bit is located in memory. Not defined and also depends on endianess.

        • Whether an int:n bitfield is to be regarded as signed or unsigned.


        Regarding the last part, C17 6.7.2.1/10 says:




        A bit-field is interpreted as having a signed or unsigned integer type consisting of the
        specified number of bits 125)




        Non-normative note explaining the above:




        125) As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int,
        then it is implementation-defined whether the bit-field is signed or unsigned.




        In case the bitfield is to be regarded as signed int and you make a bit of size 1, then there is no room for data, only for the sign bit. This is the reason why your program might give weird results on some compilers.



        Good practice:




        • Never use bit-fields for any purpose.

        • Avoid using signed int type for any form of bit manipulation.






        share|improve this answer





















        • 4





          At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

          – Michael
          Dec 19 '18 at 19:38






        • 2





          @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

          – Michael
          Dec 20 '18 at 8:25








        • 3





          @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

          – Andrew Henle
          Dec 20 '18 at 10:56








        • 2





          @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

          – mtraceur
          Dec 20 '18 at 22:41






        • 2





          @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

          – mtraceur
          Dec 20 '18 at 23:20
















        77












        77








        77







        Bit-fields are incredibly poorly defined by the standard. Given this code struct mystruct {int enabled:1;};, then we don't know:




        • How much space this occupies - if there are padding bits/bytes and where they are located in memory.

        • Where the bit is located in memory. Not defined and also depends on endianess.

        • Whether an int:n bitfield is to be regarded as signed or unsigned.


        Regarding the last part, C17 6.7.2.1/10 says:




        A bit-field is interpreted as having a signed or unsigned integer type consisting of the
        specified number of bits 125)




        Non-normative note explaining the above:




        125) As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int,
        then it is implementation-defined whether the bit-field is signed or unsigned.




        In case the bitfield is to be regarded as signed int and you make a bit of size 1, then there is no room for data, only for the sign bit. This is the reason why your program might give weird results on some compilers.



        Good practice:




        • Never use bit-fields for any purpose.

        • Avoid using signed int type for any form of bit manipulation.






        share|improve this answer















        Bit-fields are incredibly poorly defined by the standard. Given this code struct mystruct {int enabled:1;};, then we don't know:




        • How much space this occupies - if there are padding bits/bytes and where they are located in memory.

        • Where the bit is located in memory. Not defined and also depends on endianess.

        • Whether an int:n bitfield is to be regarded as signed or unsigned.


        Regarding the last part, C17 6.7.2.1/10 says:




        A bit-field is interpreted as having a signed or unsigned integer type consisting of the
        specified number of bits 125)




        Non-normative note explaining the above:




        125) As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int,
        then it is implementation-defined whether the bit-field is signed or unsigned.




        In case the bitfield is to be regarded as signed int and you make a bit of size 1, then there is no room for data, only for the sign bit. This is the reason why your program might give weird results on some compilers.



        Good practice:




        • Never use bit-fields for any purpose.

        • Avoid using signed int type for any form of bit manipulation.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Dec 19 '18 at 15:05

























        answered Dec 19 '18 at 14:51









        LundinLundin

        110k17161265




        110k17161265








        • 4





          At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

          – Michael
          Dec 19 '18 at 19:38






        • 2





          @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

          – Michael
          Dec 20 '18 at 8:25








        • 3





          @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

          – Andrew Henle
          Dec 20 '18 at 10:56








        • 2





          @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

          – mtraceur
          Dec 20 '18 at 22:41






        • 2





          @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

          – mtraceur
          Dec 20 '18 at 23:20
















        • 4





          At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

          – Michael
          Dec 19 '18 at 19:38






        • 2





          @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

          – Michael
          Dec 20 '18 at 8:25








        • 3





          @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

          – Andrew Henle
          Dec 20 '18 at 10:56








        • 2





          @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

          – mtraceur
          Dec 20 '18 at 22:41






        • 2





          @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

          – mtraceur
          Dec 20 '18 at 23:20










        4




        4





        At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

        – Michael
        Dec 19 '18 at 19:38





        At work we have static_asserts on the size and address of bitfields just to make sure that they are not padded. We use bitfields for hardware registers in our firmware.

        – Michael
        Dec 19 '18 at 19:38




        2




        2





        @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

        – Michael
        Dec 20 '18 at 8:25







        @Lundin: The ugly thing with #define-d masks and offsets is that your code gets littered with shifts and bit-wise AND/OR operators. With bitfields the compiler takes care of that for you.

        – Michael
        Dec 20 '18 at 8:25






        3




        3





        @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

        – Andrew Henle
        Dec 20 '18 at 10:56







        @Michael With bitfields the compiler takes care of that for you. Well, that's OK if your standards for "takes care of that" are "non-portable" and "unpredictable". Mine are higher than that.

        – Andrew Henle
        Dec 20 '18 at 10:56






        2




        2





        @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

        – mtraceur
        Dec 20 '18 at 22:41





        @AndrewHenle Leushenko is saying that from the perspective of just the C standard itself, it is up to the implementation whether or not it chooses to follow the x86-64 ABI or not.

        – mtraceur
        Dec 20 '18 at 22:41




        2




        2





        @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

        – mtraceur
        Dec 20 '18 at 23:20







        @AndrewHenle Right, I agree on both points. My point was that I think your disagreement with Leushenko boils down to the fact that you're using "implementation defined" to refer only to things neither strictly defined by the C standard nor strictly defined by the platform ABI, and he's using it to refer to anything not strictly defined by just the C standard.

        – mtraceur
        Dec 20 '18 at 23:20















        57















        I am unable to understand, how is it possible that we set something and then it doesn't show up as it is.




        Are you asking why it compiles vs. gives you an error?



        Yes, it should ideally give you an error. And it does, if you use your compiler's warnings. In GCC, with -Werror -Wall -pedantic:



        main.cpp: In function 'int main()':
        main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
        changes value from '1' to '-1' [-Werror=overflow]
        s.enabled = 1;
        ^


        The reasoning for why this is left up to being implementation-defined vs. an error may have more to do with historical usages, where requiring a cast would mean breaking old code. The authors of the standard may believe warnings were enough to pick up the slack for those concerned.



        To throw in some prescriptivism, I'll echo @Lundin's statement: "Never use bit-fields for any purpose." If you have the kind of good reasons to get low-level and specific about your memory layout details that would get you to thinking you needed bitfields in the first place, the other associated requirements you almost certainly have will run up against their underspecification.



        (TL;DR - If you're sophisticated enough to legitimately "need" bit-fields, they're not well-defined enough to serve you.)






        share|improve this answer





















        • 14





          The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

          – Lundin
          Dec 19 '18 at 15:00








        • 8





          There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

          – John Bollinger
          Dec 19 '18 at 15:20






        • 5





          @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

          – Lundin
          Dec 19 '18 at 15:26








        • 1





          @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

          – HostileFork
          Dec 19 '18 at 15:29






        • 1





          This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

          – Leushenko
          Dec 19 '18 at 16:00
















        57















        I am unable to understand, how is it possible that we set something and then it doesn't show up as it is.




        Are you asking why it compiles vs. gives you an error?



        Yes, it should ideally give you an error. And it does, if you use your compiler's warnings. In GCC, with -Werror -Wall -pedantic:



        main.cpp: In function 'int main()':
        main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
        changes value from '1' to '-1' [-Werror=overflow]
        s.enabled = 1;
        ^


        The reasoning for why this is left up to being implementation-defined vs. an error may have more to do with historical usages, where requiring a cast would mean breaking old code. The authors of the standard may believe warnings were enough to pick up the slack for those concerned.



        To throw in some prescriptivism, I'll echo @Lundin's statement: "Never use bit-fields for any purpose." If you have the kind of good reasons to get low-level and specific about your memory layout details that would get you to thinking you needed bitfields in the first place, the other associated requirements you almost certainly have will run up against their underspecification.



        (TL;DR - If you're sophisticated enough to legitimately "need" bit-fields, they're not well-defined enough to serve you.)






        share|improve this answer





















        • 14





          The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

          – Lundin
          Dec 19 '18 at 15:00








        • 8





          There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

          – John Bollinger
          Dec 19 '18 at 15:20






        • 5





          @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

          – Lundin
          Dec 19 '18 at 15:26








        • 1





          @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

          – HostileFork
          Dec 19 '18 at 15:29






        • 1





          This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

          – Leushenko
          Dec 19 '18 at 16:00














        57












        57








        57








        I am unable to understand, how is it possible that we set something and then it doesn't show up as it is.




        Are you asking why it compiles vs. gives you an error?



        Yes, it should ideally give you an error. And it does, if you use your compiler's warnings. In GCC, with -Werror -Wall -pedantic:



        main.cpp: In function 'int main()':
        main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
        changes value from '1' to '-1' [-Werror=overflow]
        s.enabled = 1;
        ^


        The reasoning for why this is left up to being implementation-defined vs. an error may have more to do with historical usages, where requiring a cast would mean breaking old code. The authors of the standard may believe warnings were enough to pick up the slack for those concerned.



        To throw in some prescriptivism, I'll echo @Lundin's statement: "Never use bit-fields for any purpose." If you have the kind of good reasons to get low-level and specific about your memory layout details that would get you to thinking you needed bitfields in the first place, the other associated requirements you almost certainly have will run up against their underspecification.



        (TL;DR - If you're sophisticated enough to legitimately "need" bit-fields, they're not well-defined enough to serve you.)






        share|improve this answer
















        I am unable to understand, how is it possible that we set something and then it doesn't show up as it is.




        Are you asking why it compiles vs. gives you an error?



        Yes, it should ideally give you an error. And it does, if you use your compiler's warnings. In GCC, with -Werror -Wall -pedantic:



        main.cpp: In function 'int main()':
        main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
        changes value from '1' to '-1' [-Werror=overflow]
        s.enabled = 1;
        ^


        The reasoning for why this is left up to being implementation-defined vs. an error may have more to do with historical usages, where requiring a cast would mean breaking old code. The authors of the standard may believe warnings were enough to pick up the slack for those concerned.



        To throw in some prescriptivism, I'll echo @Lundin's statement: "Never use bit-fields for any purpose." If you have the kind of good reasons to get low-level and specific about your memory layout details that would get you to thinking you needed bitfields in the first place, the other associated requirements you almost certainly have will run up against their underspecification.



        (TL;DR - If you're sophisticated enough to legitimately "need" bit-fields, they're not well-defined enough to serve you.)







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Dec 19 '18 at 18:56

























        answered Dec 19 '18 at 14:45









        HostileForkHostileFork

        25.7k779133




        25.7k779133








        • 14





          The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

          – Lundin
          Dec 19 '18 at 15:00








        • 8





          There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

          – John Bollinger
          Dec 19 '18 at 15:20






        • 5





          @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

          – Lundin
          Dec 19 '18 at 15:26








        • 1





          @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

          – HostileFork
          Dec 19 '18 at 15:29






        • 1





          This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

          – Leushenko
          Dec 19 '18 at 16:00














        • 14





          The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

          – Lundin
          Dec 19 '18 at 15:00








        • 8





          There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

          – John Bollinger
          Dec 19 '18 at 15:20






        • 5





          @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

          – Lundin
          Dec 19 '18 at 15:26








        • 1





          @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

          – HostileFork
          Dec 19 '18 at 15:29






        • 1





          This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

          – Leushenko
          Dec 19 '18 at 16:00








        14




        14





        The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

        – Lundin
        Dec 19 '18 at 15:00







        The authors of the standard were on holidays the day the bit-field chapter was designed. So the janitor had to do it. There is no rationale about anything regarding how bit-fields are designed.

        – Lundin
        Dec 19 '18 at 15:00






        8




        8





        There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

        – John Bollinger
        Dec 19 '18 at 15:20





        There is no coherent technical rationale. But that leads me to conclude that there was a political rationale: to avoid making any of the existing code or implementations incorrect. But the result is that there's very little about bitfields that you can rely upon.

        – John Bollinger
        Dec 19 '18 at 15:20




        5




        5





        @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

        – Lundin
        Dec 19 '18 at 15:26







        @JohnBollinger There was definitely politics in place, that caused a lot of damage to C90. I once spoke with a member of the committee who explained the source of lots of the crap - the ISO standard could not be allowed to favour certain existing technologies. This is why we are stuck with moronic things like support for 1's complement and signed magnitude, implementation-defined signedness of char, support for bytes that aren't 8 bits etc etc. They weren't allowed to give moronic computers a market disadvantage.

        – Lundin
        Dec 19 '18 at 15:26






        1




        1





        @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

        – HostileFork
        Dec 19 '18 at 15:29





        @Lundin It would be interesting to see a collection of writeups and post-mortems from people who believed tradeoffs had been made in error, and why. I wonder how much study of these "we did that last time, and it did/didn't work out" has become institutional knowledge to inform the next such case, vs. just stories in people's heads.

        – HostileFork
        Dec 19 '18 at 15:29




        1




        1





        This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

        – Leushenko
        Dec 19 '18 at 16:00





        This is still listed as point no. 1 of the original principles of C in the C2x Charter: "Existing code is important, existing implementations are not." ... "no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard."

        – Leushenko
        Dec 19 '18 at 16:00











        22














        This is implementation defined behavior. I am making the assumption that the machines you are running this on use twos-compliment signed integers and treat int in this case as a signed integer to explain why you don't enter if true part of the if statement.



        struct mystruct { int enabled:1; };


        declares enable as a 1 bit bit-field. Since it is signed, the valid values are -1 and 0. Setting the field to 1 overflows that bit going back to -1 (this is undefined behavior)



        Essentially when dealing with a signed bit-field the max value is 2^(bits - 1) - 1 which is 0 in this case.






        share|improve this answer


























        • "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

          – Lundin
          Dec 19 '18 at 14:56








        • 5





          @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

          – NathanOliver
          Dec 19 '18 at 15:00






        • 1





          The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

          – Lundin
          Dec 19 '18 at 15:03






        • 1





          @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

          – NathanOliver
          Dec 19 '18 at 15:08








        • 1





          @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

          – John Bollinger
          Dec 19 '18 at 15:08


















        22














        This is implementation defined behavior. I am making the assumption that the machines you are running this on use twos-compliment signed integers and treat int in this case as a signed integer to explain why you don't enter if true part of the if statement.



        struct mystruct { int enabled:1; };


        declares enable as a 1 bit bit-field. Since it is signed, the valid values are -1 and 0. Setting the field to 1 overflows that bit going back to -1 (this is undefined behavior)



        Essentially when dealing with a signed bit-field the max value is 2^(bits - 1) - 1 which is 0 in this case.






        share|improve this answer


























        • "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

          – Lundin
          Dec 19 '18 at 14:56








        • 5





          @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

          – NathanOliver
          Dec 19 '18 at 15:00






        • 1





          The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

          – Lundin
          Dec 19 '18 at 15:03






        • 1





          @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

          – NathanOliver
          Dec 19 '18 at 15:08








        • 1





          @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

          – John Bollinger
          Dec 19 '18 at 15:08
















        22












        22








        22







        This is implementation defined behavior. I am making the assumption that the machines you are running this on use twos-compliment signed integers and treat int in this case as a signed integer to explain why you don't enter if true part of the if statement.



        struct mystruct { int enabled:1; };


        declares enable as a 1 bit bit-field. Since it is signed, the valid values are -1 and 0. Setting the field to 1 overflows that bit going back to -1 (this is undefined behavior)



        Essentially when dealing with a signed bit-field the max value is 2^(bits - 1) - 1 which is 0 in this case.






        share|improve this answer















        This is implementation defined behavior. I am making the assumption that the machines you are running this on use twos-compliment signed integers and treat int in this case as a signed integer to explain why you don't enter if true part of the if statement.



        struct mystruct { int enabled:1; };


        declares enable as a 1 bit bit-field. Since it is signed, the valid values are -1 and 0. Setting the field to 1 overflows that bit going back to -1 (this is undefined behavior)



        Essentially when dealing with a signed bit-field the max value is 2^(bits - 1) - 1 which is 0 in this case.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Dec 19 '18 at 16:00









        Community

        11




        11










        answered Dec 19 '18 at 14:52









        NathanOliverNathanOliver

        93.3k16130197




        93.3k16130197













        • "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

          – Lundin
          Dec 19 '18 at 14:56








        • 5





          @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

          – NathanOliver
          Dec 19 '18 at 15:00






        • 1





          The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

          – Lundin
          Dec 19 '18 at 15:03






        • 1





          @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

          – NathanOliver
          Dec 19 '18 at 15:08








        • 1





          @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

          – John Bollinger
          Dec 19 '18 at 15:08





















        • "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

          – Lundin
          Dec 19 '18 at 14:56








        • 5





          @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

          – NathanOliver
          Dec 19 '18 at 15:00






        • 1





          The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

          – Lundin
          Dec 19 '18 at 15:03






        • 1





          @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

          – NathanOliver
          Dec 19 '18 at 15:08








        • 1





          @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

          – John Bollinger
          Dec 19 '18 at 15:08



















        "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

        – Lundin
        Dec 19 '18 at 14:56







        "ince it is signed, the valid values are -1 and 0". Who said it is signed? It's not defined but implementation-defined behavior. If it is signed, then the valid values are - and +. 2's complement doesn't matter.

        – Lundin
        Dec 19 '18 at 14:56






        5




        5





        @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

        – NathanOliver
        Dec 19 '18 at 15:00





        @Lundin A 1 bit twos compliment number only has two possible values. If the bit is set, then since it is the sign bit, it is -1. If it isn't set then it is "positive" 0. I know this is implementation defined, I'm just explaining the results using the most common implantation

        – NathanOliver
        Dec 19 '18 at 15:00




        1




        1





        The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

        – Lundin
        Dec 19 '18 at 15:03





        The key here is rather that 2's complement or any other signed form cannot function with a single bit available.

        – Lundin
        Dec 19 '18 at 15:03




        1




        1





        @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

        – NathanOliver
        Dec 19 '18 at 15:08







        @JohnBollinger I understand that. That's why I have the discliamer that this is implementation defined. At least for the big 3 they all treat int as signed in this case. It is a shame that bit-fields are so under specified. It's basically here is this feature, consult your compiler on how to use it.

        – NathanOliver
        Dec 19 '18 at 15:08






        1




        1





        @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

        – John Bollinger
        Dec 19 '18 at 15:08







        @Lundin, the standard's wording for the representation of signed integers can perfectly well handle the case where there are zero value bits, at least in two of the three allowed alternatives. This works because it assigns (negative) place values to sign bits, rather than giving them an algorithmic interpretation.

        – John Bollinger
        Dec 19 '18 at 15:08













        10














        You could think of it as that in the 2's complement system, the left-most bit is the sign bit. Any signed integer with the left-most bit set is thus a negative value.



        If you have a 1-bit signed integer, it has only the sign bit. So assigning 1 to that single bit can only set the sign bit. So, when reading it back, the value is interpreted as negative and so is -1.



        The values a 1 bit signed integer can hold is -2^(n-1)= -2^(1-1)= -2^0= -1 and 2^n-1= 2^1-1=0






        share|improve this answer




























          10














          You could think of it as that in the 2's complement system, the left-most bit is the sign bit. Any signed integer with the left-most bit set is thus a negative value.



          If you have a 1-bit signed integer, it has only the sign bit. So assigning 1 to that single bit can only set the sign bit. So, when reading it back, the value is interpreted as negative and so is -1.



          The values a 1 bit signed integer can hold is -2^(n-1)= -2^(1-1)= -2^0= -1 and 2^n-1= 2^1-1=0






          share|improve this answer


























            10












            10








            10







            You could think of it as that in the 2's complement system, the left-most bit is the sign bit. Any signed integer with the left-most bit set is thus a negative value.



            If you have a 1-bit signed integer, it has only the sign bit. So assigning 1 to that single bit can only set the sign bit. So, when reading it back, the value is interpreted as negative and so is -1.



            The values a 1 bit signed integer can hold is -2^(n-1)= -2^(1-1)= -2^0= -1 and 2^n-1= 2^1-1=0






            share|improve this answer













            You could think of it as that in the 2's complement system, the left-most bit is the sign bit. Any signed integer with the left-most bit set is thus a negative value.



            If you have a 1-bit signed integer, it has only the sign bit. So assigning 1 to that single bit can only set the sign bit. So, when reading it back, the value is interpreted as negative and so is -1.



            The values a 1 bit signed integer can hold is -2^(n-1)= -2^(1-1)= -2^0= -1 and 2^n-1= 2^1-1=0







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Dec 19 '18 at 14:57









            Paul OgilviePaul Ogilvie

            18.1k21235




            18.1k21235























                8














                As per the C++ standard n4713, a very similar code snippet is provided. The type used is BOOL (custom), but it can apply to any type.




                12.2.4



                4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold
                all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field
                shall compare equal
                .
                [ Example:



                enum BOOL { FALSE=0, TRUE=1 };
                struct A {
                BOOL b:1;
                };
                A a;
                void f() {
                a.b = TRUE;
                if (a.b == TRUE) // yields true
                { /* ... */ }
                }


                — end example ]






                At 1st glance, the bold part appears open for interpretation. However, the correct intent becomes clear when the enum BOOL is derived from the int.



                enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
                struct mystruct { BOOL enabled:1; };
                int main()
                {
                struct mystruct s;
                s.enabled = TRUE;
                if(s.enabled == TRUE)
                printf("Is enabledn"); // --> we think this to be printed
                else
                printf("Is disabled !!n");
                }


                With above code it gives a warning without -Wall -pedantic:




                warning: ‘mystruct::enabled’ is too small to hold all values of ‘enum BOOL’
                struct mystruct { BOOL enabled:1; };




                The output is:




                Is disabled !! (when using enum BOOL : int)




                If enum BOOL : int is made simple enum BOOL, then the output is as the above standard pasage specifies:




                Is enabled (when using enum BOOL)






                Hence, it can be concluded, also as few other answers have, that int type is not big enough to store value "1" in just a single bit bit-field.






                share|improve this answer






























                  8














                  As per the C++ standard n4713, a very similar code snippet is provided. The type used is BOOL (custom), but it can apply to any type.




                  12.2.4



                  4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold
                  all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field
                  shall compare equal
                  .
                  [ Example:



                  enum BOOL { FALSE=0, TRUE=1 };
                  struct A {
                  BOOL b:1;
                  };
                  A a;
                  void f() {
                  a.b = TRUE;
                  if (a.b == TRUE) // yields true
                  { /* ... */ }
                  }


                  — end example ]






                  At 1st glance, the bold part appears open for interpretation. However, the correct intent becomes clear when the enum BOOL is derived from the int.



                  enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
                  struct mystruct { BOOL enabled:1; };
                  int main()
                  {
                  struct mystruct s;
                  s.enabled = TRUE;
                  if(s.enabled == TRUE)
                  printf("Is enabledn"); // --> we think this to be printed
                  else
                  printf("Is disabled !!n");
                  }


                  With above code it gives a warning without -Wall -pedantic:




                  warning: ‘mystruct::enabled’ is too small to hold all values of ‘enum BOOL’
                  struct mystruct { BOOL enabled:1; };




                  The output is:




                  Is disabled !! (when using enum BOOL : int)




                  If enum BOOL : int is made simple enum BOOL, then the output is as the above standard pasage specifies:




                  Is enabled (when using enum BOOL)






                  Hence, it can be concluded, also as few other answers have, that int type is not big enough to store value "1" in just a single bit bit-field.






                  share|improve this answer




























                    8












                    8








                    8







                    As per the C++ standard n4713, a very similar code snippet is provided. The type used is BOOL (custom), but it can apply to any type.




                    12.2.4



                    4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold
                    all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field
                    shall compare equal
                    .
                    [ Example:



                    enum BOOL { FALSE=0, TRUE=1 };
                    struct A {
                    BOOL b:1;
                    };
                    A a;
                    void f() {
                    a.b = TRUE;
                    if (a.b == TRUE) // yields true
                    { /* ... */ }
                    }


                    — end example ]






                    At 1st glance, the bold part appears open for interpretation. However, the correct intent becomes clear when the enum BOOL is derived from the int.



                    enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
                    struct mystruct { BOOL enabled:1; };
                    int main()
                    {
                    struct mystruct s;
                    s.enabled = TRUE;
                    if(s.enabled == TRUE)
                    printf("Is enabledn"); // --> we think this to be printed
                    else
                    printf("Is disabled !!n");
                    }


                    With above code it gives a warning without -Wall -pedantic:




                    warning: ‘mystruct::enabled’ is too small to hold all values of ‘enum BOOL’
                    struct mystruct { BOOL enabled:1; };




                    The output is:




                    Is disabled !! (when using enum BOOL : int)




                    If enum BOOL : int is made simple enum BOOL, then the output is as the above standard pasage specifies:




                    Is enabled (when using enum BOOL)






                    Hence, it can be concluded, also as few other answers have, that int type is not big enough to store value "1" in just a single bit bit-field.






                    share|improve this answer















                    As per the C++ standard n4713, a very similar code snippet is provided. The type used is BOOL (custom), but it can apply to any type.




                    12.2.4



                    4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold
                    all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field
                    shall compare equal
                    .
                    [ Example:



                    enum BOOL { FALSE=0, TRUE=1 };
                    struct A {
                    BOOL b:1;
                    };
                    A a;
                    void f() {
                    a.b = TRUE;
                    if (a.b == TRUE) // yields true
                    { /* ... */ }
                    }


                    — end example ]






                    At 1st glance, the bold part appears open for interpretation. However, the correct intent becomes clear when the enum BOOL is derived from the int.



                    enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
                    struct mystruct { BOOL enabled:1; };
                    int main()
                    {
                    struct mystruct s;
                    s.enabled = TRUE;
                    if(s.enabled == TRUE)
                    printf("Is enabledn"); // --> we think this to be printed
                    else
                    printf("Is disabled !!n");
                    }


                    With above code it gives a warning without -Wall -pedantic:




                    warning: ‘mystruct::enabled’ is too small to hold all values of ‘enum BOOL’
                    struct mystruct { BOOL enabled:1; };




                    The output is:




                    Is disabled !! (when using enum BOOL : int)




                    If enum BOOL : int is made simple enum BOOL, then the output is as the above standard pasage specifies:




                    Is enabled (when using enum BOOL)






                    Hence, it can be concluded, also as few other answers have, that int type is not big enough to store value "1" in just a single bit bit-field.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Dec 20 '18 at 13:38









                    grg

                    2,47021933




                    2,47021933










                    answered Dec 20 '18 at 10:40









                    iammilindiammilind

                    44.7k20125254




                    44.7k20125254























                        1














                        There is nothing wrong with your understanding of bitfields that I can see. What I see is that you redefined mystruct first as struct mystruct { int enabled:1; } and then as struct mystruct s;. What you should have coded was:



                        #include <stdio.h>

                        struct mystruct { int enabled:1; };
                        int main()
                        {
                        mystruct s; <-- Get rid of "struct" type declaration
                        s.enabled = 1;
                        if(s.enabled == 1)
                        printf("Is enabledn"); // --> we think this to be printed
                        else
                        printf("Is disabled !!n");
                        }





                        share|improve this answer




























                          1














                          There is nothing wrong with your understanding of bitfields that I can see. What I see is that you redefined mystruct first as struct mystruct { int enabled:1; } and then as struct mystruct s;. What you should have coded was:



                          #include <stdio.h>

                          struct mystruct { int enabled:1; };
                          int main()
                          {
                          mystruct s; <-- Get rid of "struct" type declaration
                          s.enabled = 1;
                          if(s.enabled == 1)
                          printf("Is enabledn"); // --> we think this to be printed
                          else
                          printf("Is disabled !!n");
                          }





                          share|improve this answer


























                            1












                            1








                            1







                            There is nothing wrong with your understanding of bitfields that I can see. What I see is that you redefined mystruct first as struct mystruct { int enabled:1; } and then as struct mystruct s;. What you should have coded was:



                            #include <stdio.h>

                            struct mystruct { int enabled:1; };
                            int main()
                            {
                            mystruct s; <-- Get rid of "struct" type declaration
                            s.enabled = 1;
                            if(s.enabled == 1)
                            printf("Is enabledn"); // --> we think this to be printed
                            else
                            printf("Is disabled !!n");
                            }





                            share|improve this answer













                            There is nothing wrong with your understanding of bitfields that I can see. What I see is that you redefined mystruct first as struct mystruct { int enabled:1; } and then as struct mystruct s;. What you should have coded was:



                            #include <stdio.h>

                            struct mystruct { int enabled:1; };
                            int main()
                            {
                            mystruct s; <-- Get rid of "struct" type declaration
                            s.enabled = 1;
                            if(s.enabled == 1)
                            printf("Is enabledn"); // --> we think this to be printed
                            else
                            printf("Is disabled !!n");
                            }






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 4 at 1:47









                            ar18ar18

                            491




                            491






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53853540%2fwhy-is-assigning-a-value-to-a-bit-field-not-giving-the-same-value-back%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Wiesbaden

                                Marschland

                                Dieringhausen