I've been browsing stackoverflow concerning the problem of initialising a union in a struct but I didn't manage to get it right.
Here is my struct
typedef struct dc_netif_filter {
unsigned char filter_type;
union {
uint32_t itf_nb;
char * buf;
} value;
} dc_netif_filter_t;
In my code, i have tried to use :
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,{{0, "tun"}}};
which gives error: braces around scalar initializer for type ‘uint32_t’
and
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,{0, "tun"}};
which gives error: too many initializers for ‘dc_netif_filter::< anonymous union>’
How do i declare such a dc_netif_filter_t ?
I'm using g++ on ubuntu. Note that the dc_netif_filter_t isn't a struct that I can modify as it comes from a third party project.
**EDIT : as I've been explained, i can only initialise one field. The problem is that with
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,"tun0"};
I get a conversion error : invalid conversion from ‘const char*’ to ‘uint32_t
Thanks
As the compiler says, too many initializers for ‘dc_netif_filter::< anonymous union>’.
Initialize only one field, not both.
Use the name of the field to initialize it properly:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, { buf: "tun0" }};
It looks like you are trying to initialize your structure to indicate that the buf member is to be used, and that the value of that buf should be "tun". Since C++ before C++11 lacks designated initializers, you cannot do it with an initializer: only the first field of the union can be initialized, so you need to do your assignment in code:
static get_dc_netif_filter_t() {
static c_netif_filter_t netif = {DC_NETIF_SELECT_NAME, {0}};
if (netif.value.itf_nb == 0) {
netif.value.buf = "tun";
}
return netif;
}
C++11 lets you do it like this:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, { .buf = "tun"}};
This works under g++ 4.7.0:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, {.buf="tun"}};
Although designated initializers are supposed to be C only, not C++! Maybe it's a GNU extension?
I guess the best (most compatible) way is to assign the members after initialization:
dc_netif_filter_t netif;
netif.itf_nb = DC_NETIF_SELECT_NAME;
netif.value.buf = "TUN";
Related
I am importing/porting existing C code to C++. I am hoping to make as few changes to the existing body of code as possible to minimize preterbing the existing code.
This code makes use of static named initialization of nested structures. For quick made up example:
Car car =
{
.color = RED,
.tire.tread = OLD,
.tire.diameter = 27.106,
.tire.material.type = RUBBER,
.tire.material.density = 700,
};
I figured out that these are called designated initializers.
I learned about GNU initializers but I haven't figured out how to implement hierarchy with it.
I read that designated initializers are supported in g++ with c++11 enabled, but that didn't seem to work for me.
The code I am porting has pages of initialization with at least four layers deep of hierarchy. So I am trying to look for a straightforward transformation which doesn't get too involved.
I am looking for one of these possible solutions:
How to enable C99 designated initializers
How to formulate hierarchical GNU style initialization
What is a C++ equivalent way to do this which wouldn't be error prone transcribing war and peace.
An obvious solution I haven't thought of
I am using g++ version
g++.exe (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0
The use of such nested designated initializers seems to be something of an edge case. The following works in both clang-cl (in Visual Studio 2019) and the native MSVC compiler (but the latter only with the /std:c++latest option, which uses the draft C++20 standard):
struct inner {
int x, y;
double z;
};
struct outer {
char a;
double b;
inner c;
};
outer my_outer = { .a = 'a', .b = 1.2, .c = { .x = 3, .y = 4, .z = 5.6 } };
With clang-cl, the initializer can be abbreviated to the following form:
outer my_outer = { .a = 'a', .b = 1.2, .c.x = 3, .c.y = 4, .c.z = 5.6 };
but MSVC complains in this case, with:
error C7558: nested member access is not allowed in standard C++
designated initializers; use a nested initializer list
So, for your example, you could try this:
Car car =
{
.color = RED,
.tire = {
.tread = OLD,
.diameter = 27.106,
.material.type = RUBBER,
.material.density = 700,
}
};
There's a helpful 'discussion' of the topic on cppreference, with this part being notable:
...each designator must name a direct non-static data member of T, and
all designators used in the expression must appear in the same order
as the data members of T.
I would like to use some nss3.dll code in my program. To do this I decided to declare all of the compound datatypes that it needs and call the functions inside the dll file with them.
I am using a file in the firefox source code to see how to properly use the functions I need. In one of the functions it declares one of these compound datatypes (secuPWData) and passes it variables. Here is the definition I pasted into my code without any errors:
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
The declaration of this struct looks like this in the code I'm looking at: secuPWData pwdata = { PW_NONE, NULL };
When I try to use a similar (or even the same) declaration, it complains about the PW_NONE attribute, claiming it is undefined. When I tried to pass in the 0 value in its place, it told me that 'a value of type "int" cannot be used to initialize an entity of type "enum secuPWData::"'. To try to debug the issue, I tried pasting the definition right on top of the declaration, without any change.
What is causing this problem to occur?
Thanks for any help.
just as #n.m. mentioned try using secuPWData::PW_NONE
#include <iostream>
using namespace std;
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
int main() {
secuPWData pwdata = { secuPWData::PW_NONE, NULL };
return 0;
}
worked for me .. ideone - link
What is the correct way to initialize an instance of an object within matrix of struct?
My constructor Cita(int, int) need two parameters to create a new instance, but when I compile the program my shell told me I have to compile with -std=c++0x or -std=gnu++0x but I'm not allowed to do that. Here's the error..
Dia.cpp: In constructor ‘Dia::Dia(int, int, int)’:
Dia.cpp:9:56: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x [enabled by default]
Dia.cpp:9:75: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x [enabled by default]
Dia.cpp:9:75: error: deducing from brace-enclosed initializer list requires #include <initializer_list>
And here's my code..
Dia.cpp
horario_funcionarios = vector_horario_funcionarios (numero_funcionarios,
vector_horario(numero_horas, {true, Cita(0,0)}) );
Dia.hpp
struct hora_dia {
bool habil;
Cita cita;
};
typedef vector<hora_dia> vector_horario;
typedef vector<vector_horario> vector_horario_funcionarios;
class Dia {
private:
int id;
vector_horario_funcionarios horario_funcionarios;
.
.
.
Cita.cpp
Cita::Cita(int id, int nivel) {
this->id = id;
this->nivel = nivel;
}
.
.
In C++98, initializer_list is not supported i.e vectors or other containers cannot be initialized using a list {..}.
horario_funcionarios = vector_horario_funcionarios (numero_funcionarios,
vector_horario(numero_horas, {true, Cita(0,0)}) );
As g++ says, add #include <initializer_list> and compile with -std=c++0x.
The correct way to initialise a temporary POD class is to enable C++11 support and include <initializer_list>, as the compiler says. But you say you're not allowed to use modern C++ for some reason, so you'll have to do it the hard way.
One possiblity is to give hora_dia a constructor:
struct hora_dia {
hora_dia(bool habil, Cita cita) : habil(habil), cita(cita) {}
//...
};
horario_funcionarios = vector_horario_funcionarios (numero_funcionarios,
vector_horario(numero_horas, hora_dia(true, Cita(0,0))) );
or possibly a default constructor, if that makes sense:
struct hora_dia {
hora_dia() : habil(true), cita(0,0) {}
//...
};
horario_funcionarios = vector_horario_funcionarios (numero_funcionarios,
vector_horario(numero_horas) );
However, this means that the structure is no longer POD, which might be something you want. In that case, you could use a temporary object:
hora_dia hd = {false, Cita(0,0)};
horario_funcionarios = vector_horario_funcionarios (numero_funcionarios,
vector_horario(numero_horas, hd) );
or a factory function:
hora_dia make_hora_dia(bool habil, Cita cita) {
hora_dia hd = {habil, cita};
}
horario_funcionarios = vector_horario_funcionarios (numero_funcionarios,
vector_horario(numero_horas, make_hora_dia(true, Cita(0,0))) );
None of these options are ideal, which is why uniform initialisation was added to the language. You should try to persuade whoever is forbidding you from using the modern language to relax and embrace its benefits.
I'm trying to add a socket filter to one of my sockets in C++ (Linux). In the socket filter I need to get the offset of struct fork_proc_event, which is nested within another structure. The definition looks like this (cn_proc.h):
struct proc_event {
...
union {
...
struct fork_proc_event {
__kernel_pid_t parent_pid;
...
} fork;
...
} event_data;
...
};
In C I would do this:
int off = offsetof(struct fork_proc_event, parent_pid);
However I'm developing in C++. If I try to do this:
int off = offsetof(proc_event::fork_proc_event, parent_pid);
I get the following error:
error: expected type-specifier
error: expected `,'
error: expected `)' before ',' token
How should the offsetof() line look like?
It may help to think of how an implementation of an offsetof macro might go. Here's one example:
#define offsetof(TYPE, MEMBER) \
((uintptr_t)&(((TYPE*)0)->MEMBER))
In other words, using 0 as a pointer to the type you're interested in, and simply taking the address of the struct field...
So if you wanted the offset of parent_pid relative to fork (which is how I initially parsed your question):
((char*)&((struct proc_event*)0)->event_data.fork.parent_pid) - ((char*)&((struct proc_event*)0)->event_data.fork)
On second reading it sounds like you might just want the offset of parent_pid relative to the start of struct proc_event. Adapting the example above that would be:
((uintptr_t)&((struct proc_event*)0)->event_data.fork.parent_pid)
I don't exactly understand the need for all those hacks, when all you have to do is give a name to your nested union type. Any name, just to be able to refer to it in C++ code
struct proc_event {
...
union whatever {
...
struct fork_proc_event {
__kernel_pid_t parent_pid;
...
} fork;
...
} event_data;
...
};
Then you'll be able to refer to it as proc_event::whatever::fork_proc_event in offsetof in C++ code
size_t off = offsetof(proc_event::whatever::fork_proc_event, parent_pid);
If you are interested in offset of parent_pid from the beginning of proc_event, you can do
size_t off = offsetof(proc_event, event_data.fork.parent_pid);
If you cannot change the declaration, you can calculate the offset of parent_pid inside fork_proc_event by doing
size_t off =
offsetof(proc_event, event_data.fork.parent_pid) -
offsetof(proc_event, event_data.fork);
(Although I can't say right away whether the last two are formally legal examples of offsetof usage, they will normally work in practice without any problems.)
I have the following code in a C++ file:
#include <sys/socket.h>
// ...
void someFunc() {
struct msghdr msg = {0}; // <<< Uninitialized member here
}
When I compile with g++ using -Wall -Wextra, I get warnings:
error: missing initializer for member 'msghdr::msg_namelen'
...same for several other fields
My problem is this: I can't explicitly initialize all the fields, because I don't know what fields will exist (cross-platform) in a struct msghdr. The struct doesn't have a default constructor, since it's a C struct. I was under the impression that the = {0} form led to zero-initialization of all fields (which would be fine for me), but the g++ error message suggests not.
What are my options here?
Do this:
void someFunc()
{
msghdr msg = {}; // <<< All members zero-initialized
}
The g++ -Wextra warning level is IMHO not very useful.
The code that you have is also formally OK for a "C struct", in standardeese known as POD (plain old data structure). But your code explicitly initializes the first member with 0. That won't necessarily work for an aggregate that isn't POD, e.g., with a std::string as the first member, while the pure {} will work also for that.
In passing, often a POD like the one you're dealing with has a byte count as the first member, and then you can do like …
void foo()
{
SomePODStruct o = {sizeof(o)}; // The other members zero-initialized.
}
Perhaps add a STATIC_ASSERT that the byte count member is first (at offset 0).
This should work:
memset(&msg, 0, sizeof(msg));
The specific warning flag that causes this is -Wmissing-field-initializers, which is turned on as part of -Wextra. The simplest way to avoid this (bogus) warning is therefore to use -Wno-missing-field-initializers.
If you can't live with the warning and/or don't want to disable the warning, then I think it will have to be explicit initialisation via e.g. memset:
memset(&msg, 0, sizeof(msg));