How can I initialize the union in const struct? - c++

const struct EbmlSyntax {
uint32_t id;
EbmlType type;
int list_elem_size;
int data_offset;
union {
uint64_t u;
double f;
const char *s;
const struct EbmlSyntax *n;
} def;
} ;
I have to use the const struct above and want to create a a constant struct using
{ EBML_ID_DOCTYPE, EBML_STR, 0, offsetof(Ebml,doctype), {.def.s = "(none)"} }
But, the VS8.0 compiler gives an error error C2143: syntax error : missing '}' before '.' when I compiler the C++ project.
I have tried several methods ,but, I only find the way that cast the char * to uint64_t(assign to the first type),
(uint64_t)("none")
and I can use the union. Is this method safe? I check the structure of this and other struct-union object using VS debug tools.It seems OK that the member of struct and union can correctly expained.

You can only initialize the first element of the union with that syntax.
You need another approach.

Give the struct a constructor, and do the initialization
there. Of course, this isn't static initialization, but if the
struct isn't used until you're into main, that shouldn't be
a problem.
If you really need static initialization, replace the union
with a struct. This will increase the size of your object,
but this shouldn't be a big problem if it is only used for
a few objects with static initialization.

Related

Const struct initialization with custom elements in C++

I am porting some C code to C++ and I am trying to initialize a struct with some values.
I want the struct to be stored in flash (const) and not in RAM, and its values are typedef'd elements.
Originally, I had it like this:
typedef struct
{
typeA_t elementA;
typeB_t elementB;
uint8_t elementC;
} structTypeA_t;
And to instantiate them in flash, I simply did the following:
const structTypeA_t sA = {
.elementA = ONE,
.elementB = TWO,
.elementC = 3
};
I know that this type of initializing is not allowed in C++. How can I achieve it in C++?
Designated initializers are not in C++ (yet, but look for C++20). So you do it almost the same way, but without names - position of the argument defines the field it initializes:
const structTypeA_t sA = {ONE,
TWO,
3
};
If you always need to initialize with the same values, then you can just define the struct like this:
struct structTypeA_t
{
typeA_t elementA = ONE;
typeB_t elementB = TWO;
uint8_t elementC = 3;
};
You can now instantiate it without an initializer:
const structTypeA_t sA;

Typecast char array into a structure (not a class/object)

Using only ANSI-C, I was hoping to copy a byte array into a struct,
alt_u8 byteArray[16];
sMYSTRUCT myVar;
myVar = (sMYSTRUCT)(byteArray);
but seems like I need C++ for this.. however when I enable c++, I get the error
"no matching function for call to 'sMYSTRUCT::sMYSTRUCT(alt_u8 [16])"
I assume this is because the compiler doesn't know how to copy the data into the structure.. Is this correct? Is the only way to do this is define a class, create an object of that class, and THEN typecast the byte array?
typedef struct
{
alt_u8 Byte0;
alt_u8 Byte1;
} stByte_1_0;
typedef struct
{
union
{
alt_u16 WORD0;
stByte_1_0 BYTE_1_0;
} uSel;
} stWord0;
typedef struct
{
stByte_1_0 WORD0;
alt_u16 WORD1;
} sMYSTRUCT;
Such casting is undefined behavior. I would strongly suggest to avoid it.
Nevertheless, if casting is really really needed and you are sure it is safe, try
myVar = *(sMYSTRUCT*)byteArray;

how to initialize a static struct in c++?

I have managed to initialize correct any variable of basic type(i.e. int, char, float etc) but when declaring a little complex variable all i can see is errors.
In the header file timer.h i declare
class AndroidTimerConcept {
...
private:
//struct that holds the necessary info for every event
struct Resources{
timer_delegate_t membFunct;
void *data;
int size;
millis_t time;
};
//declaring an array of 10 Resources structs
static struct Resources ResData;
static int best;
...
}
inside the timer.cpp file
#include <iostream>
#include "timer.h"
using namespace std;
int AndroidTimerModel::best=1000;
struct Resources AndroidTimerModel::ResData.size; //line 17!!
//constructor that initializes all the necessary variables
AndroidTimerModel::AndroidTimerModel()
{
signal(SIGALRM,signalHandler);
for(int i=0; i<MAX_EVENTS; i++)
{
//ResData.data=NULL;
ResData.size=-1;
//ResData.time=-1;
}
best=1000;
}
when compiling the .cpp file i get the error:
timer.cpp:7: error: expected initializer before ‘.’ token
Any suggestions would be really helpful.
btw i use g++
You can use a struct initializer in C++, but only in the pre-C99 style (i.e, you cannot use designated initializers). Designated intializers, which allow you to specify the members to be initialized by name, rather than relying on declaration order, were introduced in C99, but aren't part of any C++ standard at the moment (belying the common assumption that C++ is a superset of C).
If you are willing to write non-portable C++ code that specifically targets g++, you can always use the GCC-specific extension which has the same functionality as designated constructors. The syntax is like this:
struct value_t my_val = { member_a: 1, member_b: 1.2f };
This reference provides a pretty good overview of both types of initialization in the C context.
Here's an excerpt that shows both the earlier (without designators) and C99 styles:
When initializing a struct, the first initializer in the list
initializes the first declared member (unless a designator is
specified) (since C99), and all subsequent initializers without
designators (since C99) initialize the struct members declared after
the one initialized by the previous expression.
struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0
div_t answer = {.quot = 2, .rem = -1 }; // order of elements in div_t may vary
In some cases you may need to write some code to initialize a structure, and in this case you can use the result of a function, like:
struct Resources AndroidTimerModel::ResData = function_that_acts_like_a_constructor();
You don't separately define individual instance members within a static member.
This should be enough:
AndroidTimerModel::Resources AndroidTimerModel::ResData;
You need to declare and define a constructor for struct Resources.
eg
struct Resources{
timer_delegate_t membFunct;
void *data;
int size;
millis_t time;
Resources():membFunct(0), data(0), size(0), time(0) {}
....
};
You need to initialise the whole struct variable, something like this:
AndroidTimerConcept::Resources AndroidTimerModel::ResData = { NULL, NULL, 0, 0 };
Is it AndroidTimerModel or AndroidTimerConcept, you can't use different names and expect the compiler to think they're the same thing.
You need to scope the name Resources, it's not in global scope, it's in the scope of the AndroidTimerModel class:
AndroidTimerModel::Resources AndroidTimerModel::ResData;
I suggest you give Resources a constructor:
struct Resources{
Resources(timer_delegate_t aMembFunct, void* aData, int aSize, millis_t aTime )
: membFunc(aMembFunct)
, data(aData)
, size(aSize)
, time(aTime)
{}
timer_delegate_t membFunct;
void *data;
int size;
millis_t time;
};
And you can then define Res in your .cpp as:
AndroidTimerModel::Resources AndroidTimerModel::ResData(/* params here */);
Why is your struct part of a class? I would make it global outside of the class.
memset(&structname, 0, sizeof(structname)); will initialize your structure to 0.

Referencing a union inside a structure using union tag gives incorrect address

I had a need to declare a union inside a structure as defined below:
struct MyStruct
{
int m_DataType;
DWORD m_DataLen;
union theData
{
char m_Buff [_MAX_PATH];
struct MyData m_myData;
} m_Data;
};
Initially, I tried accessing the union data as follows (before I added the m_Data declaration):
MyStruct m_myStruct;
char* pBuff = m_myStruct.theData::m_Buff;
This compiles but returns to pBuff a pointer to the beginning of the MyStruct structure which caused me to overwrite the m_DataType & m_DataLength members when I thought I was writing to the m_Buff buffer.
I am using Visual Studio 2008. Can anyone explain this unexpected behavior? Thanks.
You should be writing:
char *pBuff = m_myStruct.m_Data.m_Buff;
I wish I knew how it was compiling as written.
It shouldn't compile. GCC barfs at this code with :)
union.cpp:17: error: ‘MyStruct::theData’ is not a base of ‘MyStruct’
Don't you mean this?
char* pBuff = m_myStruct.m_Data.m_Buff;

What is the best way to initialize a bitfield struct in C++?

In C++, I have a class which contains an anonymous bitfield struct. I want to initialize it to zero without having to manually write out all fields.
I can imagine putting the initialization in three places:
Create a constructor in the bitfield
Zero out in the initializer list of the constructor for the containing class
Zero out in the body of the constructor for the containing class
This bitfield has many fields, and I'd rather not list them all.
For example see the following code:
class Big {
public:
Big();
// Bitfield struct
struct bflag_struct {
unsigned int field1 : 1;
unsigned int field2 : 2;
unsigned int field3 : 1;
// ...
unsigned int field20 : 1;
// bflag_struct(); <--- Here?
} bflag;
unsigned int integer_member;
Big *pointer_member;
}
Big::Big()
: bflag(), // <--- Can I zero bflag here?
integer_member(0),
pointer_member(NULL)
{
// Or here?
}
Is one of these preferable? Or is there something else I'm missing?
Edit: Based on the accepted answer below (by Ferruccio) I settled on this solution:
class Big {
// ...
struct bflag_struct {
unsigned int field 1 : 1;
// ...
bflag_struct() { memset(this, 0, sizeof *this); };
}
// ...
}
You could always do this in your constructor:
memset(&bflag, 0, sizeof bflag);
Union the bitfield struct with something easier to initialize to 0.
You could use a union, although that would add an extra level of indirection when accessing the fields:
class Big {
union {
struct {
unsigned int field1 : 1;
...
} fields;
unsigned int all_fields;
};
...
};
Big::Big()
: all_fields(0),
...
{
...
}
MSVC allows anonymous structs inside of unions (see, e.g. the definition of D3DMATRIX in <d3d9.h>), but this is a non-standard C++ extension which you should avoid using if you can.
BTW C++20 supports initializing the bitfields in the class definition e.g.
class ... {
int foo : 1 {};
}
gcc with -std=c++2a to enable
Your use of a function-like initializer (marked "Can I zero bflag here?") is 100% sufficient to initialize your POD struct with 0 values.
Unless you know your compiler is broken in this regard, doing any additional initialization of those members is initializing it twice for no benefit.
EDIT: Just for 'fun' I just checked this with VS2005, VS2008, GCC 3.4.4, GCC 4.2, and Borland C++ 5.5.1 ... only Borland C++ 5.5.1 gets it wrong.
And I say 'wrong' because it seems to me that 8.5 and 8.5.1 of the standard imply that the function-like initializer should zero-init the POD struct.
As an aside, unless you need the bitfield to interface to some legacy code, you shouldn't use them. They are are inherently unportable and inefficient.
you could Zero the memory using ZeroMemory or memset in the constructor that way it look's cleaner.