Initializing Unions

Hi,

I have a general 32-bit value :

typedef union { signed __int32 l ; unsigned __int32 ul ; float f ; signed __int16 n[2] ; unsigned __int16 un[2] ; signed __int8 c[4] ; unsigned __int8 uc[4] ; } tVal32 ;

you get the idea.

Now when I need to initialize these objects (e.g. in const arrays of tVal32) , I can only do it in the signed __int32 format, 'coz that's how C works.

Actually my situation is a bit more complex than this as I use tVal32 as part of a structure :

typedef struct { tVal32 Val ; tVal32 Max ; tVal32 Min ; unsigned __int32 ulAttributes ; } tParam ;

I then want to define a constant array of tParam objects, where some of the Val, Max, Min fields are float, some __int32 etc

Does anyone know a slick way of doing this ?

The only way I have found is to define individual types for each flavour of tParam (i.e. tFloatParam, tS32Param etc) and then define them as a list of individual objects, and rely on the compiler / linker putting these in order in memory as if they were and array of tParam.

This seems questionable as it produces irritating warning about unredeemed variables and assumes the compiler / linker will always lay the objects out in memory as if they were an array simply because they appear like that in the source code.

I hope I made my question clear, and any help will be appreciated.

Gary.

Reply to
Gary Pace
Loading thread data ...

unreferenced - not unredeemed !!!

tVal32)

the

of

order

out

Reply to
Gary Pace

Hi Gary,

Note that I modified the union and put the float in first position, so it initializes correctly. The sample compiles no error no warning and the result in test function (ul_foo) will be 0x00001234

If you like to have a different initialization change the order of the members.

Please read the excerpt of ANSI/ISO/IEC:9899-1999 section 6.7.8 to understand the code sample below.

to cite: "...

17 Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order,

and the first named member of a union.127)

Reply to
Jan Homuth

Jan,

Thanks for this.

What I actually want to do is to have an array of tParam objects were some of the .val fields are floats, and some __int32's and some unsigned __int32's,

i.e. I'd like to do something like :

const*/ tParam tParam_objects[3] = { {1.0F,2.0F,3.0F,0x12344321UL}, {1234L,35678L,9876L,0x23455432UL}, {0x8000000UL,0x8789761UL,0x78991231UL,0x34566543UL} };

Where element 0 has it's .val .max & .min fields initialized as type float, element 1 as type __int32 and element 2 as type unsigned __int32.

I know this isn't possible in this form in C so I'm looking for ways of achieving the same thing in a tidy manner.

Thanks. Gary

order)

initializers

union

initialize

not

union

aggregate

is

the

works.

of

unredeemed

in

Reply to
Gary Pace

[...]

If you have C99 (or a compiler that aspires to the new standard) you can use designated initializers, like so (warning: untested):

tParam param_array[] = { { {.ul = 1}, {.ul = 10}, {.ul = 0}, 0x123 }, { {.f = 3.14}, {.f = 6.28}, {.f=2.72}, 0x456 }, { {.un = {3,4}}, {.un = {5,5}}, {.un = {0,0}}, 0}, { {.uc = {[0] = 1,[1] = 0}} {.uc = {[0] = 3, [1] = 0, [2] = 0, [3] = 0}}, {.uc = {[0] = 0}}, 0x12345678 }, /* etc. */ };

Regards,

-=Dave

--
Change is inevitable, progress is not.
Reply to
Dave Hansen

Gary, try casting.

Like:

#define __int8 char #define __int16 int #define __int32 long

/*********** Note: i changed the order *************/ /* since unsigned long is the most handy format to brutally cast any "4 byte something" into, without conversion */ typedef union { unsigned __int32 ul ; float f ; signed __int32 l ; signed __int16 n[2] ; unsigned __int16 un[2] ; signed __int8 c[4] ; unsigned __int8 uc[4] ; } tVal32 ;

typedef struct { tVal32 Val ; tVal32 Max ; tVal32 Min ; unsigned __int32 ulAttributes ; } tParam ;

/* previous example , clean , with floats */ #if 0 tParam tParam_objects[3] = {\ {1.0,2.0,3.0,0x12344321UL}, {2.0,3.0,4.0,0x23455432UL}, {3.0,4.0,5.0,0x34566543UL} }; #endif

/* now mean, with unsigned long and "crowbar" casts */ tParam tParam_objects[3] = { {(unsigned long) ((float) 1.0), (unsigned long) ((float)2.0),(unsigned long) ((float)3.0),0x12344321UL}, {(unsigned long) 1234L,(unsigned long) 35678L,(unsigned long)

9876L,0x23455432UL}, {(unsigned long) 0x8000000UL,(unsigned long) 0x8789761UL,(unsigned long) 0x78991231UL,0x34566543UL} };

void union_test(void) { volatile unsigned long ul_foo;

ul_foo = (tParam_objects[0]).ulAttributes >> 16 & 0x0000FFFFUL;

}

If yo run this in the simulator/debugger and observe the content of the three objects in the data watch window, (hex display on where necessary, you can see after startup that the stuff is correctly initialized.

I've been using the TASKING M16C v2.3r1 and C166 v8.0r1 Toolchain. I assume the result will be the same in MSVC++ or Borland.

-- with kind regards

--

----------------------------------------- Jan Homuth Application Engineer Technical Support , Embedded Tools

Altium - Making Electronics Design Easier

Altium Germany GmbH Technologiepark Karlsruhe Alber-Nestler Str. 7 D-76131 Karlsruhe Phone: +49 721 8244 310 Fax: +49 721 8244 320

E-Mail: snipped-for-privacy@altium.com WWW:

formatting link

-----------------------------------------

Gary Pace schrieb in im Newsbeitrag: BObRa.65974$ snipped-for-privacy@twister.austin.rr.com...

float,

it

object.

for

results

the

If

members

the

are

aggregate

next

list

modification

Newsbeitrag:

as

of

flavour

list

objects

that

Reply to
Jan Homuth

If by correctly, Jan means that tParam_objects[0].Val.f == 1.0F, he is mistaken. The cast in the initializer only changes the type and not the value, so that tParam_objects[0].Val.ul is initialized to 1UL, and .Val.f is not defined.

See Dave Hansen's message on doing what the OP wanted in C99 (I know that Jan gave the reference earlier, but Dave gives the example). In C90, I can't think of any elegant way to do this, except for run-time assignment, rather than initialization, which won't work for ROM-based tables and also takes more code.

If faced with this, I might write a utility to initialize at run-time, then have it write a file containing unifirm initialization constants (with original values in comments), which would be included from the application program. The requires that the setup machine use the same representation for data as the target system, or that the program contains explicit conversion. The most likely conversion needed for different machines is endian adjustment.

Thad

Reply to
Thad Smith

Thad, thank you for clarification.

I agree on the runtime initialization using a function. This is the cleanest way of initializing the diversity of types.

Ouch ! You are right. The example really does an initialization of tParam_objects[0].Val.ul. to

1UL tParam_objects[0].Val.f has an undefined value.

My idea was to use the cast to assign the binary pattern created by IEEE754

32 bit single precision to tParam_objects[0].Val.ul. Bad luck. I see it now. I stumbled over the good old implicit conversion rule that is also valid for initialization.

Mea Culpa ...

/jan

Thad Smith schrieb > >

((float)2.0),(unsigned

long)

stuff is

Reply to
Jan Homuth

"Gary Pace" wrote in news:3k1Ra.89571$ snipped-for-privacy@twister.austin.rr.com:

Short of C99, I can only think two ways to do this, neither of them what I'd call "slick".

  1. Allocate and initialize the storage in assembly. Possibly in- line assembly, which I'm not a big fan of personally.
  2. Encapsulate your array in another union with a struct used only for inialization purposes, perhaps with a macro to hide the encapsulation where the array is referenced. E.g.:

union { struct { /* element 0, tParam = { f, ul, uc, ul } */ float val0_f; unsigned __int32 val0_ul; unsigned __int8 val0_uc[4]; unsigned __int32 val0_ulAttributes ; /* element 1, tParam = { l, f, ul, ul } */ signed __int32 val1_l; float val1_f; unsigned __int32 val1_ul; unsigned __int32 val0_ulAttributes ; /* etc... */ } s; tParam a[ ]; } param_array_init = { { 1.0, "abc", 3, 0xff, -1, 2.0, 3, 0xf0, /* etc... */ } };

#define param_array param_arry_init.a

That could prettify the above somewhat, especially if you only need a few of the 343 possible flavors of the tParam struct.

That is not a safe assumption, in general.

- Fred

Reply to
Fred Viles

Thanks everyone.

In the end I can up with defining a number of type specific types (tFloatPar, tS32Par etc) and then for each "parameter table" I defined a structured type listing what I needed. These could then be defined as initialized (actually const) objects.

typedef struct { tFloatParam p0 ; tFloatParam p1; tS32Param p2 ; } tParamTable ;

static const tParamTable ParamTable = { {..p0..}, {..p1..}, {..p2..} } ;

I then accessed this at run-time using my tVal32 type by :

{ tParam *ptParam ;

ptParam = (tParam*)&ParamTable ; }

Not very flexible, but since each parameter table is static to a file, it's not too bad

tVal32)

the

of

order

out

Reply to
Gary Pace

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.