C99 struct member initialization, containing UNION - struct

I'd like to declare the array of below structure,
typedef struct {
std::string key;
union {
bool b;
int i;
double d;
std::string s;
} val;
} ttt;
and initialize the arrat with C99 type, designated way.
ttt a[] = {
{
.key = std::string("key a"),
.val .. ???
How..?
Thank you!

Related

How to enumerate all member variables of a class / struct in c++

I'm working on some kind of simple reflection for c++ structs where i want to recursivly iterate over all member variables.
The code below almost does what i want but my compiler complians: "recursive type or function dependency context too complex" coming form aggregate_arity<MemberType>::size() which is based on Orients aggregate_arity implementation.
Example usage case:
struct B
{
SPVStruct;
var_t<float2_t, true> f4;
};
struct A
{
SPVStruct;
var_t<float2_t, true> f2;
var_t<float3_t, true> f3;
float d;
B b;
};
A a{};
InitializeStruct<A, true>(a);
Implementation:
struct TSPVStructTag {};
#ifndef SPVStruct
#define SPVStruct typedef TSPVStructTag SPVStructTag;
#endif
template< class, class = std::void_t<> >
struct has_spv_tag : std::false_type { };
template< class T >
struct has_spv_tag<T, std::void_t<typename T::SPVStructTag>> : std::true_type { };
template <class T>
void InitVar(T& _Member) {}
template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)
{
// actual stuff happening here
}
template <size_t N, class T, bool Assemble>
void InitStruct(T& _Struct)
{
if constexpr(N > 0u)
{
auto& member = get<N-1>(_Struct);
using MemberType = typename std::decay_t<decltype(member)>;
if constexpr(has_spv_tag<MemberType>::value)
{
constexpr size_t n = aggregate_arity<MemberType>::size(); // this is the complex recursion that blows up
InitStruct<n, MemberType, Assemble>(member);
}
else
{
InitVar(member);
InitStruct<N - 1, T, Assemble>(_Struct);
}
}
}
template <class T, bool Assemble>
void InitializeStruct(T& _Struct)
{
constexpr size_t N = aggregate_arity<T>::size();
InitStruct<N, T, Assemble>(_Struct);
}
Example
I use the has_spv_tag to mark structs that should be reflected. I can't wait for c++20 with actual reflection support :(
Thanks for your help!
Edit:
I got it to compile and changed the iteration order. Now a different problem comes up: constexpr size_t M = aggregate_arity::size() returns 0 even for the same type it returned the correct value earlier. i verified that the type is infact the same (first struct type B) by comparing the hash from typeid. How is it possible to that aggregate returns two different values for the exact same type?
template <class T, bool Assemble>
constexpr bool is_var_t(var_t<T, Assemble>& _Member) { return true; }
template <class T>
constexpr bool is_var_t(T& _Member) { return false; }
template <class T>
void InitVar(T& _Member) { std::cout << typeid(T).name() << std::endl; }
template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)
{
// actual stuff happening here
std::cout << typeid(T).name() << std::endl;
}
template <size_t n, size_t N, class T>
void InitStruct(T& _Struct)
{
std::cout << "n " << n << " N " << N << std::endl;
if constexpr(n < N)
{
decltype(auto) member = get<n>(_Struct);
using MemberType = std::remove_cv_t<decltype(member)>;
std::cout << typeid(MemberType).hash_code() << std::endl;
if (is_var_t(member))
{
InitVar(member);
InitStruct<n + 1, N, T>(_Struct);
}
else
{
constexpr size_t M = aggregate_arity<MemberType>::size();
InitStruct<0, M, MemberType>(member);
}
}
}
Edit 2: example for the new version: http://coliru.stacked-crooked.com/a/b25a84454d53d8de
Antony Polukhin pointed out the problem: MemberType still had the reference from get(_Struct). The code works with
MemberType = std::remove_reference_t<std::remove_cv_t<decltype(member)>>;
template <size_t n, size_t N, class T>
void InitStruct(T& _Struct)
{
if constexpr(n < N)
{
decltype(auto) member = get<n>(_Struct);
using MemberType = std::remove_reference_t<std::remove_cv_t<decltype(member)>>;
if constexpr(has_spv_tag<MemberType>::value)
{
InitStruct<0, aggregate_arity<MemberType>::size(), MemberType>(member);
}
else
{
InitVar(member);
}
InitStruct<n + 1, N, T>(_Struct);
}
}
I now use has_spv_tag<MemberType>::value to identify which member is a struct that i want to enumerate. There was also a bug with the order of InitStruct<n + 1, N, T>(_Struct);

Global initialization of structure

How can I initialize struct sockaddr_in globally. Third variable IN_ADDR sin_addr is a nested structure.
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
IN_ADDR sin_addr;
char sin_zero[8];
} addr;
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
};
Point 1
You cannot initalize struct sockaddr_in itself. You need to have a variable of this type, i.e, addr (as in your case) which you can initialize.
Point 2
You can use an inilitalizer list in brace-enclosed form to initialize the global variable. Also, you can make use of the .identifier option to initalize a member explicitly.
Assuming IN_ADDR is defined as
typedef struct sockaddr_in IN_ADDR;
you can write something like
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
IN_ADDR sin_addr;
char sin_zero[8];
} addr = {AF_INET, 2015, .sin_addr.S_un.S_addr = 1234567890, .sin_zero = {1,2,3,4,5,6,7}};
to initilialize addr.
Here, the .sin_addr.S_un.S_addr is used to denote to the particular variable to be initializeed.
Using your structure/union definition ... here is a sample program ...
#include <stdio.h>
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned long u_long;
typedef struct in_addr
{
union
{
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
}S_un;
}IN_ADDR;
IN_ADDR u = // ====> Either do something like this ...
{
.S_un.S_un_b = {'a', 'b', 'c', 'd'}
//.S_un.S_un_w = {1, 2},
//.S_un.S_addr = 121212
};
struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
IN_ADDR sin_addr;
char sin_zero[8];
}addr = { // ==============> Or do something like this.
10,
20,
.sin_addr.S_un.S_addr=12345,
"SOCKET"
};
int main()
{
printf("sin_family = %d\n", addr.sin_family);
printf("sin_port = %d\n", addr.sin_port);
printf("sin_addr.S_un.S_addr = %ld\n", addr.sin_addr.S_un.S_addr);
printf("sin_zero = %s\n", addr.sin_zero);
printf("%c %c %c %c\n", u.S_un.S_un_b.s_b1, u.S_un.S_un_b.s_b2, u.S_un.S_un_b.s_b3, u.S_un.S_un_b.s_b4);
//printf("%d %d\n", u.S_un.S_un_w.s_w1, u.S_un.S_un_w.s_w2);
//printf("%ld\n", u.S_un.S_addr);
return 0;
}

Interfacing with structs and anonymous unions with c2hs

How would one go about encoding this chunk of C code in a .chs file so that c2hs can transform it to something relatively nice?
typedef enum {
MONOME_BUTTON_UP = 0x00,
MONOME_BUTTON_DOWN = 0x01,
MONOME_ENCODER_DELTA = 0x02,
MONOME_ENCODER_KEY_UP = 0x03,
MONOME_ENCODER_KEY_DOWN = 0x04,
MONOME_TILT = 0x05,
/* update this if you add event types */
MONOME_EVENT_MAX = 0x06
} monome_event_type_t;
typedef struct monome monome_t; /* opaque data type */
typedef struct monome_event monome_event_t;
typedef void (*monome_event_callback_t)
(const monome_event_t *event, void *data);
struct monome_event {
monome_t *monome;
monome_event_type_t event_type;
/* __extension__ for anonymous unions in gcc */
__extension__ union {
struct {
unsigned int x;
unsigned int y;
} grid;
struct {
unsigned int number;
int delta;
} encoder;
struct {
unsigned int sensor;
int x;
int y;
int z;
} tilt;
};
};
How about this: change the code so that you name the members. The layout in memory is the same so that it will be binary compatible. You would have to do this patch for each version of the lib.
struct monome_event {
monome_t *monome;
monome_event_type_t event_type;
/* __extension__ for anonymous unions in gcc */
__extension__ union {
struct me_grid {
unsigned int x;
unsigned int y;
} grid;
struct me_encoder {
unsigned int number;
int delta;
} encoder;
struct me_tilt {
unsigned int sensor;
int x;
int y;
int z;
} tilt;
};
};

Missing type in composite literal

type A struct {
B struct {
Some string
Len int
}
}
Simple question. How to initialize this struct? I would like to do something like this:
a := &A{B:{Some: "xxx", Len: 3}}
Expectedly I'm getting an error:
missing type in composite literal
Sure, I can create a separated struct B and initialize it this way:
type Btype struct {
Some string
Len int
}
type A struct {
B Btype
}
a := &A{B:Btype{Some: "xxx", Len: 3}}
But it not so useful than the first way. Is there a shortcut to initialize anonymous structure?
The assignability rules are forgiving for anonymous types which leads to another possibility where you can retain the original definition of A while allowing short composite literals of that type to be written. If you really insist on an anonymous type for the B field, I would probably write something like:
package main
import "fmt"
type (
A struct {
B struct {
Some string
Len int
}
}
b struct {
Some string
Len int
}
)
func main() {
a := &A{b{"xxx", 3}}
fmt.Printf("%#v\n", a)
}
Playground
Output
&main.A{B:struct { Some string; Len int }{Some:"xxx", Len:3}}
do it this way:
type Config struct {
Element struct {
Name string
ConfigPaths []string
}
}
config = Config{}
config.Element.Name = "foo"
config.Element.ConfigPaths = []string{"blah"}
This is simpler imo:
type A struct {
B struct {
Some string
Len int
}
}
a := A{
struct {
Some string
Len int
}{"xxx", 3},
}
fmt.Printf("%+v", a)

Changing a struct value within a function with c++

I wanted to create a quick quadtree in c++ but found that when I change a value of a struct within a function the value reverts. Also within the recursive function I wont some of the data created to be global. How do I do this?
#include <iostream>
struct a{
unsigned int value;
struct a * leaf[4];
};
void build(struct a root, unsigned int depth){
depth++;
root.value = 0;
struct a leaf0;
root.leaf[0] = &leaf0;
struct a leaf1;
root.leaf[1] = &leaf1;
struct a leaf2;
root.leaf[2] = &leaf2;
struct a leaf3;
root.leaf[3] = &leaf3;
if (depth != 5) {
build(*root.leaf[0], depth);
build(*root.leaf[1], depth);
build(*root.leaf[2], depth);
build(*root.leaf[3], depth);
}
}
int main(int argc, const char * argv[])
{
struct a root;
root.value = 364;
build(root, 0);
std::cout << root.value;
return 0;
}
You must pass the address of the struct to your function (which should accept a pointer to the struct):
void build(struct a *root, unsigned int depth) {
...
}
int main(int argc, const char * argv[])
...
build(&root, 0);
}

Resources