C vs. C++: non-trivial designated initializers not supported

J

Johannes Bauer

Hello group,

I know this might be an implementation detail - however I do not
understand why the languages C++ and C are different in the following
example - I'm quite stunned and am looking for an explanation. Writing
some code and porting from C to C++ I encountered the error "sorry,
unimplemented: non-trivial designated initializers not supported" from
g++ 4.3.4. I boiled it down to a minimal example which compiles fine
under C, but emits that error message when compiled under C++:

typedef void (*FunctionType)(void);

typedef struct PODObject {
void *PointerValue;
FunctionType FunctionValue;
} PODObject;

void MyFunctionImpl(void);

PODObject vectorTable = {
FunctionValue: MyFunctionImpl,
};

void MyFunctionImpl() {
}


I have three options to make the code compile even when using C++:
1. Comment out the void* declaration of the PODObject
2. Change the order or PointerValue and FunctionValue
3. Define PointerValue in the struct definition

However, none of these options are really applicable in this particular
case. Is there a possibility or workaround or completely different
approach which lets me do the same thing as C does (i.e. fill the
undefined struct values with some random undefined data)?

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Jonathan Lee

Hello group,

I know this might be an implementation detail - however I do not
understand why the languages C++ and C are different in the following
example - I'm quite stunned and am looking for an explanation.

Designated initializers are a C99 feature, if I remember correctly.
Several features of C99 did not make it into the C++ specification.
I don't know if this particular one was rejected, never proposed,
planned, etc. It could have just been a matter of timing (since
the original C++ specification was 1998).

I suspect, though, that the presence of constructors in C++
makes designated initializers mostly pointless.
I have three options to make the code compile even when using C++:
  1. Comment out the void* declaration of the PODObject
  2. Change the order or PointerValue and FunctionValue
  3. Define PointerValue in the struct definition

Use #ifdef __cplusplus? It's ugly, but what do you expect
when mixing two different languages?

PODObject vectorTable = {
#ifdef __cplusplus
NULL, MyFunctionImpl
#else
FunctionValue: MyFunctionImpl
#endif
};

However, none of these options are really applicable in this particular
case. Is there a possibility or workaround or completely different
approach which lets me do the same thing as C does (i.e. fill the
undefined struct values with some random undefined data)?

Of course, if you dropped the requirement for uninitialized data
you could just fill in the first field with NULL. I highly doubt
it will create a performance hit...

--Jonathan
 
J

Johannes Bauer

Am 29.07.2010 19:08, schrieb Richard:
[Please do not mail me a copy of your followup]

Johannes Bauer <[email protected]> spake the secret code
PODObject vectorTable = {
FunctionValue: MyFunctionImpl,
};

I don't know what this is, but its not syntactically valid C or C++.

Are you sure? "gcc -Wall -Wextra -O2 -ansi -pedantic -c i.c" complains
only that it is an old form:

i.c:11: warning: obsolete use of designated initializer with ‘:’

However, it compiles, even with -ansi -pedantic. Therefore I doubt that
it's as far off the standard as your reply implies.

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

Am 29.07.2010 19:11, schrieb Jonathan Lee:
Designated initializers are a C99 feature, if I remember correctly.
Several features of C99 did not make it into the C++ specification.
I don't know if this particular one was rejected, never proposed,
planned, etc. It could have just been a matter of timing (since
the original C++ specification was 1998).

Hmm - actually it compiles with only a warning with -ansi -pedantic
-std=c89 (warning: obsolete use of designated initializer with ‘:’)
Use #ifdef __cplusplus? It's ugly, but what do you expect
when mixing two different languages?

PODObject vectorTable = {
#ifdef __cplusplus
NULL, MyFunctionImpl
#else
FunctionValue: MyFunctionImpl
#endif
};

Well, actually the point of it all was that not all fields need to be
specified. The actual vectorTable contains >150 entries of which only
about 10 will be filled usually. The point of the whole construct was so
the unused fields can be omitted.
Of course, if you dropped the requirement for uninitialized data
you could just fill in the first field with NULL. I highly doubt
it will create a performance hit...

No, initialized data is fine (viewing initialized data as a subset of
uninitialized data). Anything which was omitted may well be set to 0 or
0xffffffff or whatever the compiler likes - if it only would allow me to
omit it (like the C compiler does).

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
B

Balog Pal

Johannes Bauer said:
i.c:11: warning: obsolete use of designated initializer with ‘:’

However, it compiles, even with -ansi -pedantic. Therefore I doubt that
it's as far off the standard as your reply implies.

Designated init is definitely NOT in the C++ standard. The compiler emitted
a diagnostic for your ill-formed code, so it compiled the requirements, the
content of the message and what happens otherwise is a different issue.

More bad designated init is not in C++0x either. (Though there is
fairly enhanced {} init...)

If you want portable C++, do something else. If you're happy with what g++
does, it is an option too.
 
J

Johannes Bauer

Am 29.07.2010 19:31, schrieb Balog Pal:
Designated init is definitely NOT in the C++ standard. The compiler
emitted a diagnostic for your ill-formed code, so it compiled the
requirements, the content of the message and what happens otherwise is a
different issue.

You read me wrong. The gcc C compiler compiles the code (even with
-std=c89) and emits a diagnostic.

The g++ C++ compiler does not compile the code at all. I'm just
wondering about this (since it is pretty basic stuff, putting a struct
somewhere and having it initialized with some values).
More bad designated init is not in C++0x either. (Though there is
fairly enhanced {} init...)

If you want portable C++, do something else. If you're happy with what
g++ does, it is an option too.

Well, g++ doesn't compile it - so that's not really an option. The most
interesting question you did not answer, however: How would you
formulate the requirement in portable C? C++0x is an option, I wouldn't
mind using C++0x features.

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Jonathan Lee

Well, actually the point of it all was that not all fields need to be
specified. The actual vectorTable contains >150 entries of which only
about 10 will be filled usually.

Ouch. Er... in that case I guess you'd have to declare the variable
without an initializer (or rely on zero initialization) and then set
them one by one.

I don't really have a better solution than that. (Other than, you know
140+ unused fields sounds like a struct that wants to be rewritten...)

--Jonathan
 
A

Andrey Tarasevich

Johannes said:
I know this might be an implementation detail - however I do not
understand why the languages C++ and C are different in the following
example - I'm quite stunned and am looking for an explanation.

C++ language does not have "designated initializers", neither trivial
nor non-trivial. The same applies to C89/90 version of C language. If
you only care to initialize one specific field with an aggregate
initializer, you have to supply _all_ initializers, beginning form the
first, until you reach the field in question. The rest of the
initializers can be omitted (meaning that the rest of the struct will be
implicitly zero-initialized).
PODObject vectorTable = {
FunctionValue: MyFunctionImpl,
};

"Designated initializers" is a feature of C99 version of C language and
the proper syntax is as follows

PODObject vectorTable = { .FunctionValue = MyFunctionImpl };
I have three options to make the code compile even when using C++:
1. Comment out the void* declaration of the PODObject

??? It is not clear what you mean here.
2. Change the order or PointerValue and FunctionValue

Well, as a way to make your code shorter, it will work (see below)
3. Define PointerValue in the struct definition

??? It is not clear what you mean here.

You have the 4th way: just do it the way it has been done for ages,
without any "designated initializers". Just supply all preceding
initializers explicitly

PODObject vectorTable = { 0, MyFunctionImpl };

Your 2nd approach is just a way to get rid of that explicit leading 0.
However, none of these options are really applicable in this particular
case. Is there a possibility or workaround or completely different
approach which lets me do the same thing as C does (i.e. fill the
undefined struct values with some random undefined data)?

"Undefined struct values" do not get filled with "random undefined
data". C language follows all-or-noting approach to initialization. If
you initialize just some of the struct fields (regardless of whether you
use designated initializers or not), the rest gets implicitly zero
initialized for you.
 
A

Andrey Tarasevich

Johannes said:
Well, actually the point of it all was that not all fields need to be
specified. The actual vectorTable contains >150 entries of which only
about 10 will be filled usually. The point of the whole construct was so
the unused fields can be omitted.

If this is a _maintenance_ issue, then the way to do it portably is to
define the struct object without any initializer at all and then use
_assignment_ to set some specific fields.

If this is a _performance_ issue, the initializers will not help you
here, since in C (and in similar context in C++), initializing just one
field of the struct automatically triggers zero-initialization for _all_
fields of the struct. I.e. if you want to leave all other fields
uninitialized (for performance reasons), the way to go is again to
define the struct object without any initializer at all and then use
assignment to set some specific fields.
No, initialized data is fine (viewing initialized data as a subset of
uninitialized data). Anything which was omitted may well be set to 0 or
0xffffffff or whatever the compiler likes - if it only would allow me to
omit it (like the C compiler does).

Like _C99_ compiler does. If you want your code to be portable across
C89/90, C99 and C++ you have no other choice but to use either "no
initializer+assignment" approach or "supply all initializers beginning
from the first" approach.
 
R

Richard

[Please do not mail me a copy of your followup]

Johannes Bauer <[email protected]> spake the secret code
Am 29.07.2010 19:08, schrieb Richard:
[Please do not mail me a copy of your followup]

Johannes Bauer <[email protected]> spake the secret code
PODObject vectorTable = {
FunctionValue: MyFunctionImpl,
};

I don't know what this is, but its not syntactically valid C or C++.

Are you sure?

No. That's why I said I don't know what it is. To me it looks like a
label declaration in the middle of an aggregate initializer, which is
why I didn't think it was syntactically valid C or C++.

I didn't know about designated initializers in C99. I have been using
C++ since 1990 and haven't been following C standardization beyond
that time.

So, it turns out that for (some flavors) of C, its syntactically
valid. However, I don't see anything that indicates its ever
syntactically valid C++.

At any rate, I don't see the value added here.

From looking at other posts and [1], even the syntax used here is
wrong. So its not even syntactically valid C99.

[1]
http://publib.boulder.ibm.com/infoc....ibm.xlcpp8l.doc/language/ref/designators.htm
 
J

Johannes Bauer

Am 29.07.2010 19:53, schrieb Andrey Tarasevich:
If this is a _maintenance_ issue, then the way to do it portably is to
define the struct object without any initializer at all and then use
_assignment_ to set some specific fields.

This is not possible. The code is part of a IVT and therefore needs to
be laid out by the compiler to contain the function addresses of the ISRs.
If this is a _performance_ issue, the initializers will not help you
here, since in C (and in similar context in C++), initializing just one
field of the struct automatically triggers zero-initialization for _all_
fields of the struct. I.e. if you want to leave all other fields
uninitialized (for performance reasons), the way to go is again to
define the struct object without any initializer at all and then use
assignment to set some specific fields.

No, see above.
Like _C99_ compiler does. If you want your code to be portable across
C89/90, C99 and C++ you have no other choice but to use either "no
initializer+assignment" approach or "supply all initializers beginning
from the first" approach.

Well, that's no real nice solution. The struct has around 150 actual ISR
handlers and I want to set some specific ones without having to know
where they all need to be placed in memory.

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

Am 29.07.2010 19:38, schrieb Jonathan Lee:
Ouch. Er... in that case I guess you'd have to declare the variable
without an initializer (or rely on zero initialization) and then set
them one by one.

I don't really have a better solution than that. (Other than, you know
140+ unused fields sounds like a struct that wants to be rewritten...)

:-/

That seems to suck, is there really no other way? I cannot change the
initializers at runtime as the struct needs to be laid out in advance
and is placed in ROM (actually Flash, but ROM for that purpose).

Maybe I'll just use C-code for that part (with the correct ".foo = bar"
syntax of course) and mix the two languages. I'd really like to have
done it all in C++, though.

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

Am 29.07.2010 20:56, schrieb Richard:
[Please do not mail me a copy of your followup]

James Kanze <[email protected]> spake the secret code
It's valid C99.

Apparently not. The syntax is .member = initializer, not
member: initializer.

Yes, I used the deprecated variant. Is there anything like this in C++?

Kind regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Johannes Bauer

Am 29.07.2010 19:45, schrieb Andrey Tarasevich:
C++ language does not have "designated initializers", neither trivial
nor non-trivial. The same applies to C89/90 version of C language. If
you only care to initialize one specific field with an aggregate
initializer, you have to supply _all_ initializers, beginning form the
first, until you reach the field in question. The rest of the
initializers can be omitted (meaning that the rest of the struct will be
implicitly zero-initialized).


"Designated initializers" is a feature of C99 version of C language and
the proper syntax is as follows

PODObject vectorTable = { .FunctionValue = MyFunctionImpl };


??? It is not clear what you mean here.

When I leave out the member "PointerValue" from the struct, it works
(since all are initialized then).
Well, as a way to make your code shorter, it will work (see below)

Well, it's not possible to change the order in my case (since the layout
of the struct is determined by hardware, not by me).
??? It is not clear what you mean here.

If I define PointerValue, like say to 0...
You have the 4th way: just do it the way it has been done for ages,
without any "designated initializers". Just supply all preceding
initializers explicitly

PODObject vectorTable = { 0, MyFunctionImpl };

....like you did here, then it also works. However, I really do not want
to have to use NULL 140 times and know exactly at what positions I need
to fill the proper ISR function pointers.
Your 2nd approach is just a way to get rid of that explicit leading 0.


"Undefined struct values" do not get filled with "random undefined
data". C language follows all-or-noting approach to initialization. If
you initialize just some of the struct fields (regardless of whether you
use designated initializers or not), the rest gets implicitly zero
initialized for you.

What I meant was: It could even be filled with random data. I do not
rely on it being initialized to anything, as the data is never read
during runtime.

Regards,
Johannes

--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
J

Jonathan Lee

Am 29.07.2010 19:38, schrieb Jonathan Lee:


:-/

That seems to suck, is there really no other way? I cannot change the
initializers at runtime as the struct needs to be laid out in advance
and is placed in ROM (actually Flash, but ROM for that purpose).

The only other thing I can think of is to simply do this stuff in C
source and build that part of the tree with the C compiler :/

--Jonathan
 
F

Francesco S. Carta

Am 29.07.2010 19:53, schrieb Andrey Tarasevich:

Well, that's no real nice solution. The struct has around 150 actual ISR
handlers and I want to set some specific ones without having to know
where they all need to be placed in memory.

What is so ugly with the "no initialized + assignment" approach
suggested by Andrey?

This chunk of code isn't all that hard to type or to review, is valid
everywhere (within the context at hand) and, IIUIC, should also be
faster than the C99 version mentioned in the OP:

//-------
PODObject obj;
obj.FunctionValue = MyFunctionImpl;
//-------


And if one really wants a one-liner, one can always take advantage
(grin) of the preprocessor:

//-------
#define CREATEPOD(obj_name, member_name, value) \
PODObject obj_name; \
obj_name.member_name = value;

typedef void(*FunctionType)();

struct PODObject {
void* PointerValue;
FunctionType FunctionValue;
};

void MyFunctionImpl() {}

int main() {
CREATEPOD(obj, FunctionValue, MyFunctionImpl);
obj.FunctionValue();
}
//-------

For the records, I wouldn't use macros, I would just use the two lines I
mentioned first.
 
F

Francesco S. Carta

As Johannes stated in the part you cut out, that stuff goes to a const
segment sitting in ROM, so assignment does not play, only static init.

Sorry, I overlooked that part.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top