1

I am reading a piece of code. I believe this is in C++:

 union Float_t
 {
    Float_t(float num = 0.0f) : f(num) {}
    // Portable extraction of components.
    bool Negative() const { return (i >> 31) != 0; }
    int32_t RawMantissa() const { return i & ((1 << 23) - 1); }
    int32_t RawExponent() const { return (i >> 23) & 0xFF; }

    int32_t i;
    float f;
    #ifdef _DEBUG
    struct
    {   // Bitfields for exploration. Do not use in production code.
         uint32_t mantissa : 23;
         uint32_t exponent : 8;
         uint32_t sign : 1;
    } parts;
    #endif
};

Can someone explain two things?

1..

 Float_t(float num = 0.0f) : f(num) {}   

What is this line saying? What does f(num) mean when f isn't defined?

2.. Why are #ifdef _DEBUG and #endif necessary in the latter part of the code?

Thanks.

timrau
  • 22,578
  • 4
  • 51
  • 64
pyrrhic
  • 1,769
  • 2
  • 15
  • 27
  • 4
    You need to get a [good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list), learning by asking random questions on random bits of code is going to be a waste of time. (Especially bad code like this.) – GManNickG Aug 20 '13 at 20:16
  • 3
    Keep in mind that shifting right on a signed type (like `int`) is unspecified so this code is already walking a fine line. – Mark B Aug 20 '13 at 20:28

1 Answers1

3
Float_t(float num = 0.0f) : f(num) {} 

This is a constructor that takes a parameter that sets the value of Float_t::f. The constructor has a default parameter that sets Float_t::f to 0.0f

Example of constructor calls:

Float_t f1; // f1.f == 0.0f; is true
Float_t f2 = Float_t(3.f); // f2.f == 3.0f; is true

2.. Why are #ifdef _DEBUG and #endif necessary in the latter part of the code?

The code writer uses the information for debugging purposes and doesn't want the user of the union to access that information.

Note that the added information doesn't affect performance or memory usage if enabled in production code.

Note that all union members are at the same memory address and the following information for f1 and f2 hold

f1.f == 0.0f; // evaluates to true
f1.i == 0; // evaluates to true
f1.parts.mantissa == 0; // evaluates to true
f1.parts.exponent == 0; // evaluates to true
f1.parts.sign == 0; // evaluates to true

f2.f == 3.0f; // evaluates to true
f2.i == 1077936128; // evaluates to true
f2.parts.mantissa == 4194304; // evaluates to true
f2.parts.exponent == 128; // evaluates to true
f2.parts.sign == 0; // evaluates to true

sizeof(f1) == 4; // evaluates to true

reinterpret_cast<float&>(f2.i) == f2.f; // evaluates to true

EDIT

The constant values in the above code are obtained on a little endian configuration with the ordering of data declared as bit fields is from low to high bit

a.lasram
  • 4,371
  • 1
  • 16
  • 24
  • Cool; why does the expression f(num) automatically lead to setting f to num? And what is the colon doing there? – pyrrhic Aug 20 '13 at 20:07
  • And sorry: one last question: why was it necessary to declare this entire thing a union instead of regular struct? – pyrrhic Aug 20 '13 at 20:08
  • To put all member at the same address – a.lasram Aug 20 '13 at 20:15
  • Note that the bit-field part of the construct is platform specific; different compilers and platforms could require different organizations of the information to get the right values (but what's there might well be correct for Intel machines and most C++ compilers). – Jonathan Leffler Aug 20 '13 at 20:22
  • I get this now. Still confused about why f(num) would set the value f to num. Is there a hidden function inside the variable "f"? – pyrrhic Aug 20 '13 at 20:31
  • A constructor is a function automatically called at instantiation. It's result is the same as the function `void set(Float_t& f, float num = 0.f) {f.f = num;}` – a.lasram Aug 20 '13 at 20:33
  • 3
    @pyrrhic: It is the standard C++ notation used in constructors for initializing members from constructor arguments. It is basic C++; please read the relevant sections of your text book. – Jonathan Leffler Aug 20 '13 at 20:40