Initializing structure object using std::fill - c++

I have below a structure and need to initialize the object of it using std::fill.
typedef struct _test
{
char name[32];
char key[4];
int count;
}test;
As of now, I am using memset. I need to change it to std::fill. I have tried below but std::fill throws compiler error for the structure object.
test t;
char a[5];
std::fill(a, a + 5, 0);
std::fill(t, sizeof(t), 0);
Note: I don't want to initialize using this way. char a[5] = {0};

You don't need std::fill (or std::memset, on which you should read more here). Just value initialize the structure:
test t{};
This will in turn zero initialize all the fields. Beyond that, std::fill accepts a range, and t, sizeof(t) is not a range.
And as a final note, typedef struct _test is a needless C-ism. The structure tag in C++ is also a new type name. So what this does is pollute the enclosing namespace with a _test identifier. If you need C compatibility on the off-chance, the way to go is this
typedef struct test
{
char name[32];
char key[4];
int count;
} test;
This sort of typedef is explicitly valid in C++, despite both the struct declaration and the typedef declaring the same type name. It also allows both C and C++ code to refer to the type as either test or struct test.

Related

Import structs as nested, anonymous structs in union using C++

Please consider the following "unchangeable" declarations:
typedef struct T_MESSAGE
{
unsigned int uiTimestamp;
unsigned char ucDataType;
unsigned int uiDataSize;
unsigned char aucData[1024];
} TT_MESSAGE;
typedef struct T_SENSORDATA_HEADER
{
unsigned char ucSensorType;
unsigned char ucMountingPoint;
} TT_SENSORDATA_HEADER;
In case the message contains Sensor Data, the data is stored within the aucData array, always beginning with the Sensor Data Header. I would like to create a union or struct, which allows me to directly access all members of such a message, without having to use another variable name.
I hope you understand what I want to do by looking at my previous attempts.
I tried it like this:
union SensorDataMessage
{
struct T_Message;
struct
{
unsigned : 32; // Skip uiTimestamp
unsigned : 8; // Skip ucDataType
unsigned : 32; // Skip uiDataSize
struct T_SENSORDATA_HEADER;
};
};
and this:
struct SensorDataOverlay
{
unsigned : 32; // Skip uiTimestamp
unsigned : 8; // Skip ucDataType
unsigned : 32; // Skip uiDataSize
struct T_SENSORDATA_HEADER;
};
union SensorDataMessage
{
struct T_Message;
struct SensorDataOverlay;
};
But none of that is working. In the end, I would like to be able to write something like this:
int Evaluate(SensorDataMessage msg)
{
unsigned char tmp = msg.ucDataType;
unsigned char tmp2 = msg.ucSensorType;
[...]
}
From here I learned that what I want to do should be possible, but only in Visual C:
A Microsoft C extension allows you to declare a structure variable
within another structure without giving it a name. These nested
structures are called anonymous structures. C++ does not allow
anonymous structures.
You can access the members of an anonymous structure as if they were
members in the containing structure.
However, this seems not to be entirely true, since anonymous structs can be used in Visual C++ as well, like it is suggested here.
I would highly appreciate any help.
Here's what I found might help you out:
Have to change C/C++ compiler as Compile as C code (/TC) to gain anonymous structure support.
There's a missing keyword union on the declaration of Evaluate()
Anonymous native data type declaration in SensorDataOverlay seems would confuse the compiler, so I try to collect them into one single structure as CommonHeader, and put one pack in SensorDataOverlay.
I found T_MESSAGE and SensorDataOverlay shared the same scheme in the first three fields, I would say it would be better to be replaced as CommonHeader, would make more sense in perspective of data inheritance. Since at the beginning of question you pointed out that the T_MESSAGE is unchangeable, so I don't do any modification in the following code.
the complete code posted here, able to run, and I guess the memory offset scheme meets your needs.
*struct CommonHeader
{
unsigned int skipUiTimestamp;
unsigned char skipUcDataType;
unsigned int skipUiDataSize;
};
struct SensorDataOverlay
{
/* Use CommonHeader instead */
//unsigned : 32; // Skip uiTimestamp
//unsigned : 8; // Skip ucDataType
//unsigned : 32; // Skip uiDataSize
struct CommonHeader;
struct T_SENSORDATA_HEADER;
};
union SensorDataMessage
{
TT_MESSAGE;
struct SensorDataOverlay;
};
int Evaluate(union SensorDataMessage msg)
{
unsigned char tmp = msg.uiDataSize;
unsigned char tmp2 = msg.ucSensorType;
return 0;
}*

What is the reason for naming unions?

Why name a union if the compiler always treats the object as anonymous, regardless as to whether or not the union is named?
My implementation looks like this:
typedef struct _DMessageHeader {
union _msgId {
unsigned char ucMsgId;
unsigned short usMsgId;
unsigned long ulMsgId;
unsigned long long ullMsgId;
} msgId;
} DMSG_HDR, *PDMSG_HDR;
I'd like to be able to access it like this, but the compiler throws an error:
PDMSG_DESC ptMsg->hdr.msgId = id_in;
It only allows me to directly access the union member like this:
PDMSG_DESC ptMsg->hdr.msgId.ucMsgId = id_in;
Any thoughts as to why this is, or how I may access the union by name?
Its a type thing. The compiler can't convert an int something to a union.
You can however overload the "=" operator to do it.
I'm not sure why would you use union in this case at all.
Please note that the size of the struct is 8 bytes (size of long long) on my 64bit machine.
#include <iostream>
using std::cout;
using std::endl;
typedef struct _DMessageHeader {
union _msgId {
unsigned char ucMsgId;
unsigned short usMsgId;
unsigned long ulMsgId;
unsigned long long ullMsgId;
} msgId;
} DMSG_HDR, *PDMSG_HDR;
int main( int argc , char ** argv, char ** env)
{
cout<<"sizof DMessageHeader"<<sizeof(DMSG_HDR)<<endl;
return 0;
}
If all you store in union msgid is a single id of varying length (1 - 8) bytes depending on your architecture) and you have no memory constrains rewrite your struct as following:
typedef struct _DMessageHeader {
unsigned long long msgId;
} DMSG_HDR, *PDMSG_HDR;
DMSG_HDR hdr;
hdr.msgId = id_in;
Also I suggest reading this thread for thorough discussion about using unions in C++.
There can be various reasons:
There are restrictions in original C compiler which doesn't allow anonymous unions. In other words the structure may be used by both C and C++ programs.
You may want to work with whole union (moving, assigning etc.) and this allows you to define the variable of such types.
Because you're not using an anonymous union in your example. You've given your union member of your struct a name, msgId, and it has members. You can't assign directly to the union itself, you have to assign to a member of the union.
An anonymous union would be as follows:
union {
int i;
char c;
};
i = 1;
or
struct s
{
int i1;
union {
int i2;
char c2;
};
};
s s1.i2 = 5;
The union in struct s has no name, and it's members are accessed directly.
ETA:
Assuming your variable id_in is an unsigned char since you assign it to the unsigned char member in the example that works, why would you expect this to work?
PDMSG_DESC ptMsg->hdr.msgId = id_in;
ptMsg->hdr.msgId is not of type unsigned char nor is it an implicitly convertible type. ptMsg->hdr.msgId is of type _DMessageHeader::_msgId.
"A union is a special class type that can hold only one of its non-static data members at a time." (http://en.cppreference.com/w/cpp/language/union) It's a class type and you've defined no conversion operators or constructors. Of course it won't allow the assignment.

Can I use an enum as a struct name?

I think it may be called literal?
enum packet_structures{
PacketOne,
PacketTwo,
PacketThree
};
struct PacketOne{
unsigned int packet_id;
};
struct PacketTwo{
unsigned int packet_id;
};
struct PacketThree{
unsigned int packet_id;
};
And let's say I have a general packet.
struct PacketGeneral{
packet_structures TypeOfPacket;
};
PacketGeneral newPacket;
newPacket.TypeOfPacket = PacketOne;
Can I literally use that enum's name to typecast a char* to a struct (i.e PacketOne)? Without having to typecast with (struct PacketOne), how can I just typecast that same struct but with just the enumeration newPacket.TypeOfPacket?
No you cannot. Enums are used for storing literals and not identifiers.
No, at least not in C.
enum declares/defines constant identifiers.
So, you cannot use those same identifier again as structure tag name.
You can check that by compiling a program containing these declarations/definitions.

Passing struct of array as reference c++

I am new to structure programming, and I find it quite confusing when trying to pass a structure of array in c++. I have a project to do for college, a Star Trek game. This is the sample code:
void main_menu(char,char [][sz2],int&,struct enterpriseSt*,struct klingonSt*[100]);
void combat_menu(char [][sz2],struct enterpriseSt*,int&,struct klingonSt*[100]);
struct enterpriseSt
{
int energy_level;
int damage;
int torpedo_count;
};
struct klingonSt
{
int energy_level;
int damage;
int position[2];
};
int main()
{
struct enterpriseSt enterprise;
enterprise.energy_level=energy_ent_max;
enterprise.damage=0;
enterprise.torpedo_count=10;
struct klingonSt klingon[100];
main_menu(command,galaxy,turn,&enterprise,&klingon);
return 0;
}
void main_menu(char command, char galaxy[][sz2],int& turn,struct enterpriseSt * enterprise,struct klingonSt * klingon[100])
{
combat_menu(galaxy,enterprise,turn,klingon);
}
I have two structures, enterpriseSt and klingonSt. I can pass enterprise no problem, but with klingon I am struggling. I get all kinds of errors, doesn't matter what combination I use. The current one is:
error: cannot convert ‘klingonSt (*)[100]’ to ‘klingonSt**’ for argument ‘5’ to ‘void main_menu(char, char (*)[64], int&, enterpriseSt*, klingonSt**)’
I've made such a mess with it now. Could someone please explain it to me why it works with enterprise but not with klingon?
I use g++ compiler on Ubuntu. Thanks.
Your problem is in misunderstanding the arguments parsing rules.
you think that struct klingonSt*[100] is a pointer to the array of size 100 of type struct klingonSt, but actually when argument parsing, array and function symbols that should be situated on the right of token has higher priority, than symbols on the left of expression.
So, lets first write the expression with argument name included:
struct klingonSt*var[100]
and parse it
var
is an array of size 100 (as array symbol on the right has higher priority, than pointer on the left)
of pointers
to the type struct klingonSt
so, struct klingonSt*var[100] is actually is array of size 100 of pointers to struct klingonSt.
to pass a pointer to the array of size 100 of type struct klingonSt you should change parsing precedence using parenthesis:
struct klingonSt(*var)[100]
or
struct klingonSt(*)[100]
If you change your definition, your code will compile fine.
I think you're a bit confused on passing arrays to functions. When this is done, the array decays into a pointer to the first element of the array. You can declare the parameter as an array, but the array range is ignored by the compiler, and not enforced at runtime. Thus, for this style of coding, you'd just want to pass the array as a pointer, and length as a separate parameter (I've omitted your other params for clarity):
void main_menu(enterpriseSt*, int enterpriseCount, klingonSt*, int klingonCount);
Some alternatives to consider:
Adopting a modern C++ style, and use std containers like vector/list, passing them by reference.
void main_menu(vector<enterpriseSt> & enterprises, vector<klingonSt> & klingons);
Or, using a template wrapper to pass sized local arrays implicitly:
template<size_t eCount, size_t kCount>
void main_menu(enterpriseSt (&enterprises)[eCount], klingonSt (&klingons)[kCount])
{
main_menu(enterprises, eCount, klingons, kCount);
}
The problem that
struct klingonSt * klingon[100]
is an array of 100 struct klingonSt * rather than a point to 100 struct klingonSt
use struct klingonSt klingon[][100] instead.

C/C++: size of a typedef struct containing an int and enum == sizeof(int)?

I am using gcc version 4.3.3 on my Ubuntu (i686). I have written a stripped down test program to describe my lack of understanding and my problem. The program shall tell me the size of the struct, which I implemented. So I have a typedef struct for a Message and a little main to play around:
#include <stdio.h>
typedef struct {
int size;
enum {token=0x123456};
} Message;
int main(int argc, char * argv[])
{
Message m;
m.size = 30;
printf("sizeof(int): %d\n",sizeof(int));
printf("sizeof(0x123456): %d\n",sizeof(0x123456));
printf("sizeof(Message): %d\n",sizeof(Message));
printf("sizeof(m): %d\n",sizeof(m));
}
While compiling this source with gcc I get the following warning, which I don't understand:
$ gcc sizeof.c
sizeof.c:5: warning: declaration does not declare anything
Line 5 refers to the enum line. I want that token in every Message, that I create. What am I doing wrong? What do I have to change to get rid of that warning?
My main contains several calls of sizeof(). When I run the program, you can see in the output that the integer has the size of four, the hex number has the size of 4, but the typedef struct Message has the size of 4, too:
$ ./a.out
sizeof(int): 4
sizeof(0x123456): 4
sizeof(Message): 4
sizeof(m): 4
That is very confusing to me. Why has Message the size of 4, although it contains an integer and an integer within an enum, each with the size of 4. If the sizeof(Message) would be at least 8, it would be logical to me.
But why is it only 4? How do I get the real size in Bytes of my Message? Or is this really the real size? If so, why?
Is there a difference in getting the size of a Message between C and C++?
An enumeration doesn't actually need any space, it's just a way for the compiler to recognize a set of literal numbers by a name.
You are not declaring anything with:
enum {token=0x123456};
Your declaration is similar to:
typedef struct {
int size;
int;
} Message;
If you declare your struct like this:
typedef struct {
int size;
enum {token=0x123456} e;
} Message;
There will be two fields, but e will not be initialized to anything. You need to set it manually for every instance: message.e=token.
The correct way to achieve what you want is, to use constructors in C++:
struct Message {
int size;
int token;
Message() : token(0x123456) {};
};
Or non-static data member initializers in C++11:
struct Message {
int size;
int token=0x123456;
};
There is no way to initialize field in struct declaration in C.
Line 5 does not declare any variable that is of type enum. So the compiler does the only thing it can do: ignore it.
If you want to create a member of that type in the struct, write something like
enum {token=0x123456} thetoken;
But be aware that this field can only have one valid value, is that what you want?
Edit:
Oh, and to answer your other question: I can't see a difference in output when compiling as C or C++. But there is a difference between how how you should write struct definitions.
typedef struct {
int size;
enum YouShouldDeclareAName {token=0x123456};
} Message;
your enum is a subclass/subtype of your Message struct, therefore bounds to Class and not object. Like a namespace. You do not create any variable with it.
Change it to:
typedef struct {
int size;
enum YouShouldDeclareAName {token=0x123456} token;
//or
YouShouldDeclareAName token2;
} Message;
You've defined a constant Message::token that's shared between all objects. Since it's shared, it doesn't count towards the size of a single object.
As the others answers note, you've declared an enumerated type, you just happened to do it inside a structure instead of at global scope. There's nothing to store, so it uses no memory.
Now if you were to declare an instance of your enumeration in that structure...
typedef struct {
int size;
enum {token=0x123456} e;
} Message;
int main(int argc, char * argv[])
{
Message m;
m.size = 30;
printf("sizeof(m): %d\n",sizeof(m));
}
sizeof(m): 8
Press any key to continue . . .
LINE 5:
enum {token=0x123456};
This line doesn't define any enum variable, its a declaration, because of this your compiler complains about line 5 saying its only a declaration.
proper usage should be:
enum {xyz=5} enum_variable_name;
Only then the compiler will allocate space for this.
Just like class, function, enum, static menber doesn't store in the object space!