This question already has answers here:
C++ Structure Initialization [duplicate]
(17 answers)
Closed 2 years ago.
I'm a trying to migrate some legacy C code for Embedded targets to C++ for compatibility issues and I am encountering some issues with unions in C++.
in our project we have the following style of union to reduce the amount of RAM usage:
typedef union unionTest
{
struct
{ uint32_t nField1:5
; uint32_t nField2:4
; uint32_t nField3:23
;}
; uint32_t nRaw ///< Raw data
;} unionTest;
// A global variable for configuration
unionTest myCUnion = {.nField1 = 1, .nField2 = 2, .nField3 = 3 };
This works well, is easy to use and the compiler initializes the bit fields at the correct values at compile time
Then when converting to C++
typedef union unionTest
{
struct
{ uint32_t nField1:5
; uint32_t nField2:4
; uint32_t nField3:23
;}
; uint32_t nRaw ///< Raw data
;} unionTest;
// Using const saves RAM, one of the reason to switch to C++
const unionTest myCppUnion = {.nField1 = 1, .nField2 = 2, .nField3 = 3 }; // Error
does not work anymore, I have a "too many initializers" error. Is there anyway to keep the C behavior. I know that anonymous structures are prohibited by ISO C++ but changing this has a huge impact on the code base, and was not judged important for now.
And I also tried with a named struct
typedef union unionTest
{
struct notAnonymous
{ uint32_t nField1:5
; uint32_t nField2:4
; uint32_t nField3:23
;} notAnonymous
; uint32_t nRaw ///< Raw data
;} unionTest;
// Using const saves RAM, one of the reason to switch to C++
const unionTest myCppUnion2 = {.notAnonymous.nField1 = 1, .notAnonymous.nField2 = 2, .notAnonymous.nField3 = 3 }; // expected primary-expression before '.' error
const unionTest myCppUnion3 = { .notAnonymous = { .nField1 = 1, .nField2 = 2, .nField3 = 3 } }; // Compiles
and I can't find a solution that keeps the original C behavior.
I have not yet tested if the solution "myCppUnion3" fills the bitfields correctly, but I a m more interested by finding a solution/workaround for solution "myCppUnion"
If anyone has any leads I'll glady take them !
In C++ you need an extra set of braces to reflect that the initializers are in a sub-struct:
const unionTest myCppUnion = { {.nField1 = 1, .nField2 = 2, .nField3 = 3 } };
I have a "too many initializers" error.
The solution to this is simple. You need a set of braces to explicitly express that you are initialising the nested class within the union:
{ // the union
{ // the struct
.nField1 = 1, // members of the struct
.nField2 = 2,
.nField3 = 3,
}
};
I know that anonymous structures are prohibited by ISO C++
Indeed, that is another thing that must be fixed for C++. With that fixed, you can use a designated initaliser for the struct as in your example.
Third problem you'll likely encounter is that C++ does not allow reading from an inactive union member, which seems likely to be what you do in C.
Fourth potential problem is that if you ever switch the compiler, you may find that the order of your bitfields changes which may be a problem if your program relies on particular order.
Related
I am using a library with a struct that has 3 officially documented members, but its implementation actually contains 4. The last one is a byte array that is used for padding. This is a common technique in C to stay ABI compatible: add a bunch of bytes at the end, and if later versions add members to the struct, this padding area is shrunk accordingly. In total, the size of the struct stays the same.
But now I have to use this struct in C++, and I am using it for a static const value, so I need to initialize it using an initializer list. So, like this:
static const foo_struct foo = { 1, 2, 3 };
Since this does not initialize the fourth value, GCC prints out:
warning: missing initializer for member ‘foo_struct::padding’ [-Wmissing-field-initializers]
A constructor syntax like foo(1,2,3) would not work, since this is a C struct. And setting it to {0} is no option either, since I must initialize the first three members.
Is there a C++11/C++14 conform way of dealing with this warning?
EDIT: Simply using { 1, 2, 3, 0 } might work, but is unstable, since the padding area is undocumented. Also, if future versions add a member, then it would sum up to 5 members, and the warning would return.
You can just write a function like this:
template <class ... T>
constexpr foo_struct make_foo_struct(T ... t) {
return foo_struct{t..., 0};
}
static const auto foo = make_foo_struct(1, 2, 3);
You don't need to disable any warnings. As a bonus, if another field is added to the struct, the warning will come back (because you'll then have 5 members, and you're only initializing 4). This is also convenient because if you are creating lots of foos, and a new field is added that you don't care about (say it's a boolean, that you always want to be true), you can change make_foo_struct to initialize it the way you want, without modifying all of the call sites.
You can of course write out the types and argument names in make_foo_struct instead of using T...; it makes things more explicit but also requiring more maintenance and less flexible.
If the padding is removed, this should just fail to compile, and again you would only need to fix this one function. But if you don't like that, another option is to locally silence the warning with a compiler pragma, just in the function.
template <class ... T>
constexpr foo_struct make_foo_struct(T ... t) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
return foo_struct{t...};
#pragma GCC diagnostic pop
}
And to hell with it, I'll give a third option. If you there are 3 named members, and their names are stable, and you want to simply initialize them and zero out the rest, you can do:
constexpr foo_struct make_foo_struct(int x, int y, int z) {
foo_struct f{};
f.x = x; f.y = y; f.z = z;
return f;
}
The compiler should happily optimize this out.
C++ was made with compatibility with C in mind...
Since the library structure is a C struct, pad the bytes exactly as you would do it in C. While the padding bytes are undocumented, they are part of the struct definition, using a fourth initializer (a zero) will be fine, and is needed. You actually have no choice but to fill the pad bytes to zero.
Example:
// in the library .h
struct foo_struct
{
int first, second, third;
unsigned char padding[256 - 3 * sizeof(int)];
};
// in your cpp
// your could do this:
static const foo_struct foo1 = { 1, ,2, 3, 0 }; // add 0, since it's needed.
// or if you really want to create this boiler plate...
static const foo_struct foo2; // note that it is initialized to zero at startup
// as all static variables are, unless a value is specified
static bool InitFoo2();
static bool fooInitialized = InitFoo2(); // it does waste some data space...
static bool InitFoo2()
{
p = const_cast<foo_struct*>(&foo2);
memset(p, 0, sizeof(foo2)); // not needed in this particular case
// but doesn't hurt to do be explicit.
p->first = 6;
p->second = 7;
p->third = 42;
return true;
}
// Top keep your code compatible with future version, you have no choice,
// but to clear the padding bytes of any foo_struct before using the library.
// Let's look at dynamic allocation, the required data space is the
// exact same size as for static memory allocation.
//
foo_struct* bar()
{
// sizeof(foo_struct) = 256 bytes, padding MUST be reset,
// so your app is compatible with future versions of the library.
//
foo_struct* p = (foo_struct*)malloc(sizeof(foo_struct));
if (p)
{
// By clearing the foo_struct this way, you do not ever need to
// the undocumented members.
memset(p, 0, sizeof(*p));
p->first = 6;
p->second = 7;
p->third = 42;
}
return p;
}
I'd personally go for this solution:
static const foo_struct foo = { 6, 7, 42, 0 };
Say I have such a class:
enum class Flags : char
{
FLAG_1 = 1;
FLAG_2 = 2;
FLAG_3 = 4;
FLAG_4 = 8;
};
Now can I have a variable that has type flags and assign a value 7 for example? Can I do this:
Flags f = Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3;
or
Flags f = 7;
This question arises because in the enum I have not defined value for 7.
You need to write your own overloaded operator| (and presumably operator& etc.).
Flags operator|(Flags lhs, Flags rhs)
{
return static_cast<Flags>(static_cast<char>(lhs) | static_cast<char>(rhs));
}
Conversion of an integer to an enumeration type (scoped or not) is well-defined as long as the value is within the range of enumeration values (and UB otherwise; [expr.static.cast]/p10). For enums with fixed underlying types (this includes all scoped enums; [dcl.enum]/p5), the range of enumeration values is the same as the range of values of the underlying type ([dcl.enum]/p8). The rules are trickier if the underlying type is not fixed - so don't do it :)
It's maybe better to make use of std::underlying_type instead of hard-coding char type.
Flags operator|(Flags lhs, Flags rhs) {
return static_cast<Flags>(
static_cast<std::underlying_type<Flags>::type>(lhs) |
static_cast<std::underlying_type<Flags>::type>(rhs)
);
}
Now, you can change the underlying type of your enumeration without needing to update that type in every bitwise operator overload.
It should handle any enumeration type. I'm not sure it doesn't have any side effects and is completely valid C++ code. Let me know if there are some issues.
template<class T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
constexpr T operator|(T lhs, T rhs)
{
return static_cast<T>(
static_cast<std::underlying_type<T>::type>(lhs) |
static_cast<std::underlying_type<T>::type>(rhs));
}
Please don't do this. If you need to do this, enum classs probably aren't what you need.
#T.C. showed you how to do it so long as you specify underlying type, but you will run into places where your program does things it just shouldn't.
An example is where you use a switch and have a case for every defined enum value.
e.g.
enum class my_enum: unsigned int{
first = 1,
second = 2,
third = 4,
fourth = 8
};
int main(){
auto e = static_cast<my_enum>(static_cast<unsigned int>(my_enum::first) | static_cast<unsigned int>(my_enum::second));
switch(e){
case my_enum::first:
case my_enum::second:
case my_enum::third:
case my_enum::fourth:
return 0;
}
std::cout << "Oh, no! You reached a part of the program you weren't meant to!\n";
return 1;
}
Will output:
Oh, no! You reached a part of the program you weren't meant to!
then return the error code 1.
Which is also an example of why you should always have a default case, of course, but that isn't my point.
Of course, you could argue that so long as the user of the enum class never directly uses the value other than passing to a function; it would be a good way of restricting the values of a bitset. But I've always been a little too trustworthy and find std::uint[n]_t and some constexpr variables the best way (if a user sets an invalid bit it simply does nothing).
What you're doing just isn't really suitable for enum class, because it defeats the purpose of having a scoped enumeration. You can no longer enumerate the values if you set it to an undefined one.
I realize this question is a bit old, but I will write out a method I have used to do this.
(If anything, if I Google this again in the future I have it documented to find again.)
Personally I like this method because intellisense (at least the VSCode version of it... I don't have Visual Studio on Linux...) will automatically pick up on what you're doing and give you useful hints. Also, it avoids the use of macros, so the compiler can warn you if it is not happy. Lastly, without the comments, it isn't a lot of code. You're not making a class and setting a bunch of overloads or anything, but you're still getting the benefit of scoped enums so that you can reuse a flag name/value for another enum. Anyway onto the example.
namespace FlagsNS
{
/* This is an old/classic style enum so put it in a
namespace so that the names don't clash
(ie: you can define another enum with the values of
Flag_1 or Flag_2, etc... without it blowing up)
*/
enum Flags
{
Flag_1 = 1 << 0, //Same as 1
Flag_2 = 1 << 1, //Same as 2
Flag_3 = 1 << 2, //Same as 4
Flag_4 = 1 << 3 //Same as 8
};
}
/* This is telling the compiler you want a new "type" called Flags
but it is actually FlagsNS::Flags. This is sort of like using the
#define macro, except it doesn't use the preprocessor so the
compiler can give you warnings and errors.
*/
using Flags = FlagsNS::Flags;
//Later in code.... so int main() for example
int main()
{
//If you don't mind c-style casting
Flags flag = (Flags)(Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3);
//Or if you want to use c++ style casting
Flags flag = static_cast<Flags>(Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3);
//Check to see if flag has the FLAG_1 flag set.
if (flag & Flags::FLAG_1)
{
//This code works
}
}
The code in question doesn't compile. But you can do something like this,
enum class Flags : char
{
FLAG_1 = 1,
FLAG_2 = 2,
FLAG_3 = 4,
FLAG_4 = 8,
};
int main() {
Flags f = static_cast<Flags>(7);
Flags f1 = static_cast<Flags>( static_cast<char>(Flags::FLAG_1) | static_cast<char>(Flags::FLAG_2) | static_cast<char>(Flags::FLAG_3) );
return 0;
}
and it works
At this point, It probably makes sense to define your own class to handle this.
/** Warning: Untested code **/
struct Flag {
static Flag Flag_1;
static Flag Flag_2;
static Flag Flag_3;
static Flag Flag_4;
Flag operator = (Flag);
private:
char const value;
};
Flag operator | (Flag, Flag);
The CDT parser reports a syntax error for the structure initialization:
typedef struct MyStruct
{
int a;
float b;
};
int main( void )
{
// GNU C extension format
MyStruct s = {a : 1, b : 2};
// C99 standard format
// MyStruct s = {.a = 1, .b = 2};
return 0;
}
While GCC lists the : form as obsolete, it would seem that it has not been deprecated nor removed. In C99 I would certainly use the standard .<name> = form but for C++, the : is the only option that I am aware of for designated initialization.
I have tried setting my toolchain to both MinGW and Cross GCC, but neither seem to work.
How can I get Eclipse to recognize this syntax? It's not a big deal for one line but it carries through to every other instance of the variable since Eclipse does not realize it is declared.
The . form is only available in C99 and not in any flavor of C++. In C++ your only standards-compliant options are ordered initialization or constructors.
You can use chaining with appropriate reference returning methods to create a similar interface (here a and b are methods rather than variables):
MyStruct s;
s.a(1).b(2);
I meet this problems too and i use below method to solve it.
MyStruct s = {
1,
2,
}
This requires programmer to ensure sequence of initialization.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Should I use #define, enum or const?
Advantage and disadvantages of #defines vs. constants?
How enum will be more useful than #define and const.
memory and code visibilty point of view and readability point of view.
can I convert (type cast) enum to array of int, If I have taken all value within integer.
Example:
class MapPlt_clContainer {
public:
enum tagVectorType {
enVTAll = 0,
enVTPolygon,
enVTLines
}
};
tVoid MapPlt_clRender::vDrawLineClass( MapPlt_clContainer::tagVectorType* )
While calling function enum pass
vDrawLineClass( ClassArray_Group ); //Working
While calling array base address pass
int test[3] =
{
5,
6,
7,
};
vDrawLineClass( test); //Not Working
Error!!
Should it type cast it automatically? or it is compiler dependent. In my case it is giving error.
enum is a separate type unlike #define and the language (with the help of compiler) will help you ensure you are not mixing values of different types (even if they are of the same numerical value).
Additionally the value of an enum is available to the debugger whereas the original meaning of the #define is lost during the pre-processing time (before the code generation has even begun).
Type-casting an enum to an int is an automatic built-in process while the opposite conversion is trickier as not all the int values could be valid for your particular enum.
Modern compilers will also warn you if you have used all the possible enum's values in a switch statement that has no default clause, something that cannot be checked for #defines
If you are using an enum as an integer in C++ you have a smell. An enum defines a type, and only the values of that type should be used. (I realize this isn't enforced and the enum can be interpreted as an int, but with C++ it generally shouldn't).
Also, a big pet peeve of mine: Don't put "Type" in the name for an enum in C++. The values of an enum are not "types" (in the C++ sense of the word). As soon as you start doing template code, you will HATE all the enums with the word Type in their type name.
Also, any time you are trying to typecast in your design, you are doing it wrong. That is an awful smell in C++. You shouldn't have to do it, and you certainly shouldn't design it into your code (i.e. use it as a "feature").
Finally, this part:
int test[3] =
{
5,
6,
7,
};
vDrawLineClass( test); //Not Working
This is a straight up ugly hack. Do what you say, say what you do:
MapPlt_clContainer::tagVectorType test[3] =
{
MapPlt_clContainer::enVTAll,
MapPlt_clContainer::enVTPolygon,
MapPlt_clContainer::enVTLines
};
vDrawLineClass( test);
In addition to the points made in other answers, I would like to add the following:
If you have multiple types and you need to iterate on them, you will have to use an array of constants, which will be something like this:
const int states[] = {STATE_1,STATE_2, STATE_3, STATE_4 };
int numStates = sizeof(states)/sizeof(state[0]);
for (int i = 0; i < numStates; i++) {
// Do something with states[i]..
}
With enumerations, this can be simplified as
enum states{cState_1 = 0, cState_2, cState_3, cState_4, cNumStates};
for (int i = 0; i < numStates; i++) {
// do something with i
}
I did some research but cannot find a definite approval or disapproval.
What I want is, a fixed size structure + variable length part, so that serialization can be expressed in simple and less error prone way.
struct serialized_data
{
int len;
int type;
char variable_length_text[0];
};
And then:
serialize_data buff = (serialize_data*)malloc(sizeof(serialize_data)+5);
buff->len=5;
buff->type=1;
memcpy(buff->variable_length_text, "abcd", 5);
Unfortunately I can't find if MSVC, GCC, CLang etc., are ok with it.
Maybe there is a better way to achieve the same?
I really don't want those ugly casts all around:
memcpy((char*)(((char*)buffer)+sizeof(serialize_data)), "abcd", 5);
This program is using a zero length array. This is not C but a GNU extension.
http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
A common idiom in C89, called the struct hack, was to use:
struct serialized_data
{
int len;
int type;
char variable_length_text[1];
};
Unfortunately its common use as a flexible array is not strictly conforming.
C99 comes with something similar to perform the same task: a feature called the flexible array member.
Here is an example right from the Standard (C99, 6.7.2.1p17)
struct s { int n; double d[]; };
int m = 12; // some value
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));