Not all “true” are created equal


 

During a review of some low level bit manipulation logic a developer raised a question about the correctness of a piece of code which allowed any arbitrary byte to be seen as a bool.  No one could recall if true was defined as not 0 or simply 1.  If it was the latter then the code was allowing for a large range of invalid bool values to be created.  A quick look at the CLI spec revealed the immediate answer (partition III section 1.1.2)

A CLI Boolean type occupies 1 byte in memory. A bit pattern of all zeroes denotes a value of false. A bit pattern with any one or more bits set (analogous to a non-zero integer) denotes a value of true.

A quick test backed up this particular assertion.  Any non-zero value is true and 0 is indeed false.  We took the test one step further and discovered, to the surprise of about half of us, that just because two bool values are true, doesn’t mean they’re equal.  

    class Program
    {
        [StructLayout(LayoutKind.Explicit)]
        struct Union
        {
            [FieldOffset(0)]
            internal byte ByteField;

            [FieldOffset(0)]
            internal bool BoolField;
        }

        static void Main(string[] args)
        {
            Union u1 = new Union();
            Union u2 = new Union();
            u1.ByteField = 1;
            u2.ByteField = 2;
            Console.WriteLine(u1.BoolField); // True
            Console.WriteLine(u2.BoolField); // True
            Console.WriteLine(u1.BoolField == u2.BoolField); // False
        }
    }

I was one of those who was surprised Smile

Comments (8)

  1. KooKiz says:

    Which means that, somehow, comparing u1.BoolField to 'true' and u1 to u2 doesn't call the same code…

  2. KooKiz says:

    Keeping the same value of u2 as your sample:

               bool b = true;

               Console.WriteLine(u2.BoolField == b); // False

               Console.WriteLine(u2.BoolField == true); // True

    I'm mind-blown!

  3. KooKiz says:

    Oh I get it. The line 'Console.WriteLine(u2.BoolField == true); ' is rewritten by the compiler as 'Console.WriteLine(u2.BoolField);'. So we're directly calling the bool overload of the Console.WriteLine method, and not doing the actual comparison.

    Sorry for the comments spam 😉

  4. Jared – You have a great blog; thanks for posting all of this! Your articles on DebuggerDisplay and similar attributes are really useful to my project. Just to let you know, I've made several modifications to your FlattenHierarchyProxy class (from blogs.msdn.com/…/flattening-class-hierarchies-when-debugging-c.aspx). A key modification is the ability to only "promote" (as I am calling it) members from base classes that you specify with attributes.

    I will be releasing the upgraded class on BitBucket. If you are interested, my blog is at http://www.mostthingsweb.com/. Thanks again for your work,

    Chris

  5. JaredPar says:

    Interesting.  I look forward to seeing the article on your blog

  6. MostThingsWeb says:

    The repository is up: bitbucket.org/…/basememberpromotingproxy. Still probably needs lots of optimization, but the basic ideas are there. Please let me know if you would like to attributed a different way in the source.

  7. jaredpar says:

    I took a look at the project.  It looks very nice!