I have the following code declared in my header file:
//Integer Vector4D stuffs
typedef union {
size_t data[4];
struct {
size_t x;
size_t y;
size_t z;
size_t w;
};
struct {
size_t x;
size_t y;
size_t width;
size_t height;
};
} Vector4Di;
//End Integer Vector4D stuffs
I am compiling the code for Windows and Linux. I'm using Windows 10 Pro with WSL.
This is my compilation build output taken from Microsoft Visual Studio 2017:
1>------ Build started: Project: SDL, Configuration: Debug x64 ------
1>C:main_pc.cpp
1>1 File(s) copied
1>block.cpp
1>common.cpp
1>draw.cpp
1>game.cpp
1>input.cpp
1>main.cpp
1>Generating Code...
1>SDL.vcxproj -> C:\Users\tom_mai78101\Documents\VSProjects\SDL\x64\Debug\SDL.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Given the above build log, this shows that the build has succeeded when compiling.
That same source code, however, would throw errors in GCC:
$ make
clean ...
build ...
main.cpp
In file included from /mnt/c/Users/tom_mai78101/Documents/VSProjects/SDL/SDL/../SDL/main.cpp:1:0:
/mnt/c/Users/tom_mai78101/Documents/VSProjects/SDL/SDL/../SDL/game/common.h: At global scope:
/mnt/c/Users/tom_mai78101/Documents/VSProjects/SDL/SDL/../SDL/game/common.h:358:10: error: redeclaration of 'size_t <unnamed union>::<unnamed struct>::x'
size_t x;
^
/mnt/c/Users/tom_mai78101/Documents/VSProjects/SDL/SDL/../SDL/game/common.h:352:10: note: previous declaration 'size_t <unnamed union>::<unnamed struct>::x'
size_t x;
^
/mnt/c/Users/tom_mai78101/Documents/VSProjects/SDL/SDL/../SDL/game/common.h:359:10: error: redeclaration of 'size_t <unnamed union>::<unnamed struct>::y'
size_t y;
^
/mnt/c/Users/tom_mai78101/Documents/VSProjects/SDL/SDL/../SDL/game/common.h:353:10: note: previous declaration 'size_t <unnamed union>::<unnamed struct>::y'
size_t y;
^
The gist is, in GCC, it would complain about how size_t x; and size_t y; are both redeclared inside the union, Vector4Di. But MSBuild doesn't throw errors in regards to this, and it successfully compiled the code.
To my knowledge, I believed unions with same types and same variable names should not be in conflict with another, especially when the variables are in a struct. Especially when compiling for C++11, where it was known that C++11 has better support for unions.
May I ask why it is throwing the error for GCC? And how should I fix this error so both MSBuild and GCC both compiled successfully?
Thanks in advance.
The C++ standard does not admit anonymous struct not being used to define a member of its type inside a union; using an anonymous struct to inject its members in the enclosing union is just a widespread extension, but it's not standard C++, so it's not strictly well-defined how this mechanism works.
In particular, here you are treading in dangerous waters, as you are having two anonymous structs with members with the same names; from the C++ standard point of view this is definitely murky, as it is ambiguous what is the "active union member" when you do e.g. v4d.x = 5;.
VC++ documentation does not describe what happens in this case; a quick check tells me that it doesn't get mad even if the names refer to conflicting memory locations - it just seems to refer to the member of the first anonymous struct being defined, which is completely nuts if you ask me.
gcc instead does get mad, as it's like declaring two members with the same name in the same struct; its documentation actually says:
You must never create such structures that cause ambiguous field definitions. For example, in this structure:
struct {
int a;
struct {
int a;
};
} foo;
it is ambiguous which a is being referred to with foo.a. The compiler gives errors for such constructs.
So, this isn't something you can work around with compiler switches or something; gcc doesn't support it, period.
This vision is confirmed by the only standard where this feature is actually described formally, which is the ISO C 11 standard; there, at §6.7.2.1 ¶13, it is said:
An unnamed member of structure type with no tag is called an anonymous structure; an unnamed member of union type with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.
and named members of a struct are required to have unique names.
So, to recap:
if you want this to become standard C++, you have to give some names to your sub-structures; you can do:
union Vector4Di {
size_t data[4];
struct {
size_t x;
size_t y;
size_t z;
size_t w;
} q;
struct {
size_t x;
size_t y;
size_t width;
size_t height;
} r;
};
adjust the rest of your code and be happy with it.
if you are ok with using those extensions, you can still make it somehow work by naming x and y differently in the second struct, as in:
union Vector4Di {
size_t data[4];
struct {
size_t x;
size_t y;
size_t z;
size_t w;
};
struct {
size_t dummy_x;
size_t dummy_y;
size_t width;
size_t height;
};
};
in this case you could freely work with x and y and width and height, and I suspect it's even pretty much ok standard-wise - if we ignore the "anonymous struct" thing; the two structs are standard-layout and are layout-compatible, so the standard guarantees that you can inspect the "common initial sequence" using whatever names you prefer.
Ok, this is something I learned today. And that is C++ does not play nicely with anonymous structs / unions. According to the comments, I should add tag names to the structs and unions.
So this is the new modified version:
//Integer Vector4D stuffs
typedef union {
size_t data[4];
struct quaternion {
size_t x;
size_t y;
size_t z;
size_t w;
} quaternion;
struct rect {
size_t x;
size_t y;
size_t width;
size_t height;
} rect;
} Vector4Di;
//End Integer Vector4D stuffs
Now, both Visual Studio and GCC compile the same project and source codes just fine, and no longer throw errors about the redeclaration of variables of same names and same types. I also don't need to modify the rest of the codes to accommodate the new changes, despite that this Vector4Di struct is declared in the headers, so this is a great fix.
Thanks to MatteoItalia for the help.
This question already has answers here:
storage size of ‘names’ isn’t known
(3 answers)
Closed 4 years ago.
I am trying myself out at bluetooth programming and came along this problem I do not understand. Basically, when I am using the typedef struct defintion the compiler throws the error:
temp_testcode.c:11:23: error: storage size of ‘head’ isn’t known
The code, compiled simply via gcc temp_testcode.c is as follows:
#include <stdint.h>
typedef struct {
uint8_t code;
uint8_t ident;
uint16_t len;
} __attribute__ ((packed)) l2cap_cmd_hdr;
/**
struct l2cap_cmd_hdr {
uint8_t code;
uint8_t ident;
uint16_t len;
};
*/
int main(int argc ,char* argv[]) {
struct l2cap_cmd_hdr head;
}
Though once I use the lower definition of a struct (currently commented out) the code compiles perfectly fine. So either it's a problem with the typedef struct or with the __attribute__ ((packed))
The previous stackoverflow posts about typedef structs did not help me out (typedef struct vs struct definitions), since I do not know how to make the the struct initialization in the main method work using the typedef struct (and not my currently commented out version). Something which is necessary because the bluetooth header files all define their structs like this.
So:
How do I make the struct initialization in the main method work using the typedef struct?
Why doesn't my code work?
Thank you for your time and help!
Typedefs and structs are in two different namespaces. That means the typedef l2cap_cmd_hdr is distinct from the struct struct l2cap_cmd_hdr.
You're trying to create an instance of the latter, which doesn't exist. You do have an instance of an anonymous struct that is typedef'ed as l2cap_cmd_hdr, so you can create that:
l2cap_cmd_hdr head;
I get byte redefinition error when I try to compile my application. One is defined in Crypto++ library and the other one in rpcdnr.h of Windows Kit. I tried many things but none worked. Any idea to solve the problem is appreciated.
typedef unsigned char byte;
Thanks
P.S. I'm using Qt on Windows.
Namespaces were created for this reason so to avoid interference between identifiers define them under a namspace:
namespace crypto{
typedef unsigned char byte;
};
namespace rpcndr{
typedef unsigned char byte;
};
int main(){
crypto::byte bValue = 7;
rpcndr::byte bvalue2 = 10;
ret
}
I am having a bit of trouble with the following include:
#include <ntddscsi.h>
When I compile (using NetBean 7.1 & Cygwin C++ compiler), I am told that I need to define "SCSI_PASS_THROUGH" before I can use it... in ntddscsi.h however, it is defined:
typedef struct _SCSI_PASS_THROUGH {
SHORT Length;
CHAR ScsiStatus;
CHAR PathId;
CHAR TargetId;
CHAR Lun;
CHAR CdbLength;
CHAR SenseInfoLength;
CHAR DataIn;
LONG DataTransferLength;
LONG TimeOutValue;
LONG_PTR DataBufferOffset;
LONG SenseInfoOffset;
CHAR Cdb[16];
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
Anyone have any idea what on earth is going wrong??
This might happen if you have circular dependencies, or for example LONG_PTR is not defined anywhere.
Been awhile since I've used structs in C++.
Any idea why this isn't working? My compiler is complaining about DataStruct not being a recognized type but Intellisense in VC++ is still able to see the data members inside the struct so the syntax is ok...
Frustating. xD
struct DataStruct
{
int first;
};
int main(int argc, char **argv)
{
DataStruct test;
//test.first = 1;
}
Are you sure you are compiling the file as C++? If you compile it as C (i.e. if the file has a .c rather than a .cpp extension), you will have problems.
You are compiling as C code. C requires you to refer to it using the "Struct" keyword or typedef it. C++ does not.
You need to use struct DataStruct to refer to the struct.
Alternatively, you can typedef it as DataStruct if don't want to use the "struct" everywhere.