Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

union within a struct - problems with initialization

2,282 views
Skip to first unread message

derell...@gmail.com

unread,
Dec 9, 2013, 2:45:13 PM12/9/13
to
I've been programming C for over 25 years, but this is one problem I've never been able to solve; I'm hoping someone here can help me with it.

The program which follows, can act on several different data types; the arg_type_t field selects which of the actual data fields will be acted on for each table entry. In the past, I skipped the union and just carried fields for all possible data types - but this is very inefficient, because all the data fields need to be present in each line, but only one is ever actually valid.

So I want to include a union of all the different data types that I can support, but I cannot figure out how to initialize the actual table. When I try to build the following program, I get compilation errors on each line of the table:

c:\sourcecode\win32\config Yes, Master?? > g++ -Wall -O2 -s config.cpp -o config.exe
config.cpp:41: error: too many initializers for `config_entry_t'
config.cpp:41: error: too many initializers for `config_entry_t'
config.cpp:41: error: too many initializers for `config_entry_t'
config.cpp:41: error: too many initializers for `config_entry_t'

c:\sourcecode\win32\config Yes, Master?? > g++ --version
g++ (GCC) 3.4.5 (mingw special)
Copyright (C) 2004 Free Software Foundation, Inc.

Is there some way I can handle the table instantiation so that this union will actually be valid ?

Dan Miller
Fremont, CA

// My program:
//**********************************************************************
// Copyright (c) 2013 Daniel D Miller
// config.cpp - this will eventually evolve into a class for handling
// INI-file-based configuration sy stems.
// Unlike my previous attempts at such a task, this one will support
// category headers in the file.
//**********************************************************************

#include <stdio.h>

typedef unsigned int uint ;

typedef enum arg_type_e {
ARG_END=0,
ARG_INT,
ARG_UNSIGNED,
ARG_BOOL,
ARG_DOUBLE,
ARG_STRING
} arg_type_t ;

typedef struct config_entry_s {
char *name ;
arg_type_t arg_type ;
union t {
int *i ;
uint *u ;
bool *b ;
double *d ;
char *s ;
};
} config_entry_t, *config_entry_p ;

static uint uint_var = 0 ;
static double dbl_var = 0.0 ;
#define CHAR_VAR_LEN 80
static char char_var[CHAR_VAR_LEN+1] ;

config_entry_t global_table[4] = {
{ "uvalue", ARG_UNSIGNED, &uint_var },
{ "dvalue", ARG_DOUBLE, &dbl_var },
{ "svalue", ARG_STRING, &char_var[0] },
{ "end", ARG_END, NULL }} ;

int main(void)
{
return 0;
}

Andrei Voropaev

unread,
Dec 24, 2013, 2:12:20 PM12/24/13
to
On 2013-12-09, derell...@gmail.com <derell...@gmail.com> wrote:
> So I want to include a union of all the different data types that I
> can support, but I cannot figure out how to initialize the actual
> table. When I try to build the following program, I get compilation
> errors on each line of the table:
>
....
I don't know about Windows and C++ but normal gcc (4.7.3) accepts
following definition and initialization.

typedef struct {
char *name;
arg_type_t arg_type;
union {
int *i;
uint *u;
bool *b;
double *d;
char *s;
};
} config_entry_t, *config_entry_p;

config_entry_t global_table[4] = {
{ "uvalue", ARG_UNSIGNED, { .u = &uint_var }},
{ "dvalue", ARG_DOUBLE, { .d = &dbl_var }},
{ "svalue", ARG_STRING, { .s = char_var }},
{ "end", ARG_END, { .s = NULL }}
};

Note, that to access specific union field you use global_table[0].i or
global_table[1].u and so on. You can also provide a name for the
union field, but you put it AFTER fields declaration, not before it. Ie.
union { int * i; uint *u } t; Then the initiation does not change but to
access it you'd have to say global_table[0].t.i.


--
Minds, like parachutes, function best when open

derell...@gmail.com

unread,
Jan 20, 2014, 3:51:27 PM1/20/14
to
On Tuesday, December 24, 2013 11:12:20 AM UTC-8, Andrei Voropaev wrote:
Ahhh... interesting... this indeed works with gcc, but not with g++ :
Yes, Master?? > g++ -Wall -O2 -s union.struct.cpp -o union.struct.exe
union.struct.cpp:31:33: error: expected primary-expression before '.' token
union.struct.cpp:32:31: error: expected primary-expression before '.' token
union.struct.cpp:33:31: error: expected primary-expression before '.' token
union.struct.cpp:34:25: error: expected primary-expression before '.' token

This is with g++ (tdm-1) 4.6.1

I tried giving the included union a type name, and specifying the fields as:
config_entry_t global_table[4] = {
{ "uvalue", ARG_UNSIGNED, { config_entry_t.types_t.u = &uint_var }},
{ "dvalue", ARG_DOUBLE, { config_entry_t.types_t.d = &dbl_var }},
{ "svalue", ARG_STRING, { config_entry_t.types_t.s = char_var }},
{ "end", ARG_END, { config_entry_t.types_t.s = NULL }}
};

but that still is not valid... Unfortunately, I build everything with g++, so the C-only solution isn't really viable for me. My guess is, though, that there *is* a way for me to correctly specify those type fields, if I can just figure out what it is!!

Thanks for the lead, Andrei !!

derell...@gmail.com

unread,
Jan 20, 2014, 4:08:57 PM1/20/14
to
Okay, I found the answer in another thread elsewhere:

config_entry_t global_table[4] = {
{ (char *) "uvalue", ARG_UNSIGNED, { u: &uint_var }},
{ (char *) "dvalue", ARG_DOUBLE, { d: &dbl_var }},
{ (char *) "svalue", ARG_STRING, { s: char_var }},
{ (char *) "end", ARG_END, { i: &unused_int }}
};

This builds without warnings via the command:

derell...@gmail.com

unread,
Jan 20, 2014, 4:21:31 PM1/20/14
to
Just for completeness, here is the entire buildable test program:

//*************************************************************************
// Copyright (c) 2014 Daniel D Miller
// This utility is freeware, usable for any purpose,
// commercial or otherwise.
//
// static initialization of union within struct
// build with: g++ -Wall -O2 -s union.struct.cpp -o union.struct.exe
//*************************************************************************

#include <stdio.h>
typedef unsigned int uint ;

typedef enum arg_type_e {
ARG_END=0,
ARG_INT,
ARG_UNSIGNED,
ARG_BOOL,
ARG_DOUBLE,
ARG_STRING
} arg_type_t ;

typedef union types_u {
int *i;
uint *u;
bool *b;
double *d;
char *s;
} types_t ;

typedef struct {
char *name;
arg_type_t arg_type;
types_t t ;
} config_entry_t, *config_entry_p;

static uint uint_var = 3254 ;
static double dbl_var = 58.74 ;
#define CHAR_VAR_LEN 80
static char char_var[CHAR_VAR_LEN+1] = "derelict was here" ;

config_entry_t global_table[4] = {
{ (char *) "uvalue", ARG_UNSIGNED, { u: &uint_var }},
{ (char *) "dvalue", ARG_DOUBLE, { d: &dbl_var }},
{ (char *) "svalue", ARG_STRING, { s: char_var }},
{ (char *) "end", ARG_END, { s: NULL }}};

//*******************************************************************
int main(void)
{
uint idx ;
for (idx=0; global_table[idx].arg_type != ARG_END; idx++) {
switch (global_table[idx].arg_type) {
case ARG_INT:
printf("found int: %d\n", *global_table[idx].t.i) ;
break;
case ARG_UNSIGNED:
printf("found uint: %u\n", *global_table[idx].t.u) ;
break;
case ARG_BOOL:
printf("found bool: %s\n", (*global_table[idx].t.b) ? "true" : "false") ;
break;
case ARG_DOUBLE:
printf("found double: %.1f\n", *global_table[idx].t.d) ;
break;
case ARG_STRING:
printf("found string: %s\n", global_table[idx].t.s) ;
break;
case ARG_END:
break;
}
}

return 0;
}
0 new messages