40

I have built a working C library, that uses constants, in header files defined as

typedef struct Y {
  union {
    struct bit_field bits;
    uint8_t raw[4];
  } X;
} CardInfo;

static const CardInfo Y_CONSTANT = { .raw = {0, 0, 0, 0 } };

I know that the .raw initializer is C only syntax.

How do I define constants with unions in them in a way such that I can use them in C and C++.

9
  • 1
    are you sure about the mixed-mode tag? Commented Jul 19, 2012 at 7:17
  • 2
    Isn't C++ initializing the unions by the first element? I.e. static const Y_CONSTANT = {{0,0,0,0}}; Commented Jul 19, 2012 at 7:19
  • @YePhIcK then it gives additional warnings about missing braces. Commented Jul 19, 2012 at 7:22
  • @Alex - I just tried my code and it built fine with no errors/warnings. Are you sure you are using double-braces? typedef struct Y { union { struct bit_field bits; uint8_t raw[4]; } X; } CardInfo; static const CardInfo Y_CONSTANT = {{0, 0, 0, 0 } }; Commented Jul 19, 2012 at 7:31
  • 1
    That is correct and that is how the language is - you are allowed to initialize the FIRST element of the union and only the first one Commented Jul 19, 2012 at 7:32

5 Answers 5

25

I had the same problem. For C89 the following is true:

With C89-style initializers, structure members must be initialized in the order declared, and only the first member of a union can be initialized

I found this explanation at: Initialization of structures and unions

Sign up to request clarification or add additional context in comments.

Comments

7

I believe that C++11 allows you to write your own constructor like so:

union Foo
{
    X x;
    uint8_t raw[sizeof(X)];

    Foo() : raw{} { }
};

This default-initializes a union of type Foo with active member raw, which has all elements zero-initialized. (Before C++11, there was no way to initialize arrays which are not complete objects.)

4 Comments

@Alex: No, of course not. But with luck the structure will be layout-compatible with a similarly declared C structure...
Ah I see so you want to suggest to use #ifdef __cplusplus on the right places to make that header file includeable. Ah that might get even more fuzzy.
Warning : adding a constructor removes PODness, which is often desirable when messing with unions for memory access.
@Offirmo C++11 introduced a new term standard-layout class , these are allowed to have constructors; and many cases which required POD in C++03 now only require standard-layout. (POD is now defined as standard-layout plus some other guarantees).
3

I decided to choose the following path.

  • Do not use .member initialization.
  • do nost use static const struct Foobar initialization of members

Instead declare the global variable:

extern "C" {
  extern const struct Foobar foobar;
}

and initialize it in a global section:

struct Foobar foobar = { 0, 0, 0, 0 };

and instead of bugging the C++ compiler with modern ANSI C99 syntax I let the linker do the work be demangling C symbols.

Comments

0

This is my example how to make const union in C99 (also works in C++).

#include <stdio.h>
#include <stdint.h>

typedef union{
    uint16_t u16;
    uint8_t u8s[sizeof(uint16_t)];
}uint8_16_t;

int main()
{
    const uint8_16_t val= {.u8s={0xAA, 0xBB}};
    printf("0x%04X", val.u16);
    return 0;
}

out: 0xBBAA

Comments

0

The .raw initializer (designated initializer) is added in C++20

// ok for c++20 or higher
static const CardInfo Y_CONSTANT = { .raw = {0, 0, 0, 0 } };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.