Discussion:
Initialize array of structs with structs?
(too old to reply)
Randall Parker
2008-06-13 15:58:49 UTC
Permalink
We've got a struct:

struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
};

Then we do things like:
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
and Msg3, 4, etc..


Then we want to do:
struct msgStruct MsgArray[] = {
Msg1,
Msg2,
etc.....
};

Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept. CG's compiler expects to see
unsigned int,
unsigned char *,
unsigned int,
unsigned char *,
unsigned int,
unsigned char *,

So I figured the problem was with the outer squiggly brackets. So I tried this:

struct msgStruct MsgArray[] =
Msg1,
Msg2,
etc.....
;

Then it complained about how a { was expected.

How can I do this? I do not want to put all the int and char* values in the initialization of the array. First off, a large amount of code does it this other way with struct vars first declared. Second, we reuse the same message in different arrays. I do not want duplicates with the possibility of inconsistencies.
Duane Hebert
2008-06-13 16:32:56 UTC
Permalink
Post by Randall Parker
struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
};
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
and Msg3, 4, etc..
struct msgStruct MsgArray[] = {
Msg1,
Msg2,
etc.....
};
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily
accept. CG's compiler expects to see
unsigned int,
unsigned char *,
unsigned int,
unsigned char *,
unsigned int,
unsigned char *,
struct msgStruct MsgArray[] =
Msg1,
Msg2,
etc.....
;
Just curious but does the behavior change if you drop the struct
keyword? Like
msgStruct MsgArray[]=...
Remy Lebeau (TeamB)
2008-06-13 16:39:53 UTC
Permalink
<snip>
Post by Randall Parker
Well, CG CB 2007 objects to this syntax
What is the exact error?

CG's compiler expects to see
Post by Randall Parker
unsigned int,
unsigned char *,
unsigned int,
unsigned char *,
unsigned int,
unsigned char *,
That is what you declared in the structs. But the actual constants you are
using are likely being seen by the compiler as 'int' and 'char*' instead.
Post by Randall Parker
So I figured the problem was with the outer squiggly brackets.
Nope. Those are needed since you are defining an array.


Gambit
Randall Parker
2008-06-13 21:08:07 UTC
Permalink
Post by Remy Lebeau (TeamB)
<snip>
Post by Randall Parker
Well, CG CB 2007 objects to this syntax
What is the exact error?
E2034 Cannot convert 'msgStruct' to 'unsigned int'
E2034 Cannot convert 'msgStruct' to 'unsigned char *'
E2034 Cannot convert 'msgStruct' to 'unsigned int'
E2034 Cannot convert 'msgStruct' to 'unsigned char *'
E2034 Cannot convert 'msgStruct' to 'unsigned int'
E2034 Cannot convert 'msgStruct' to 'unsigned char *'
E2034 Cannot convert 'msgStruct' to 'unsigned int'
E2034 Cannot convert 'msgStruct' to 'unsigned char *'
... and more of the same

If I was specifying each field in each struct right there I expect to have needed to use inner squigglies to denote each entry:
MyStructArray[] =
{ {5, "Dogs"},
{5, "Cats"},
};

So I'm surprised that the compiler thinks it knows when to move to the next field of the next struct without the extra layering of {}.
Eliot Frank
2008-06-13 18:17:35 UTC
Permalink
Post by Randall Parker
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
and Msg3, 4, etc..
struct msgStruct MsgArray[] = {
Msg1,
Msg2,
etc.....
};
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept.
It's not creating a copy constructor. You need to add a constructor to
your struct. The following does compile under CB2007:

struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char const *pMsg;
msgStruct(unsigned sz, char const *p): msgSize(sz), pMsg(p) {};
};

struct msgStruct Msg1(6,"Hello");
struct msgStruct Msg2(9,"Good bye");

struct msgStruct MsgArray[] = {
Msg1,
Msg2
};

-Eliot
Duane Hebert
2008-06-13 18:45:42 UTC
Permalink
Post by Eliot Frank
Post by Randall Parker
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
and Msg3, 4, etc..
struct msgStruct MsgArray[] = {
Msg1,
Msg2,
etc.....
};
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept.
It's not creating a copy constructor. You need to add a constructor to
struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char const *pMsg;
msgStruct(unsigned sz, char const *p): msgSize(sz), pMsg(p) {};
};
But his version didn't have pMsg as a const *. Why wouldn't
the compiler be able to create a default copy ctor for a struct
with an int and a char*?
Eliot Frank
2008-06-13 19:00:37 UTC
Permalink
Post by Duane Hebert
Post by Randall Parker
struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char const *pMsg;
msgStruct(unsigned sz, char const *p): msgSize(sz), pMsg(p) {};
};
But his version didn't have pMsg as a const *. Why wouldn't
the compiler be able to create a default copy ctor for a struct
with an int and a char*?
Yes, I changed the OP's code to get it to compile. I made pMsg const so
I could initialize pMsg with a const *. Maybe you could const_cast it
away. (pMsg should be const anyway the way it is being used.)

My point is that the compiler was not creating a copy construct for the
OP's original code. I assume (1) that the compiler does not create the
copy constructor until it is needed, (2) the compiler sees the C-like
initialization of the Msg1, Msg2 instances, and so (3) decides that a
C++ copy constructor should not be used. I'm just guessing.

-Eliot
Duane Hebert
2008-06-13 19:54:12 UTC
Permalink
Post by Eliot Frank
Yes, I changed the OP's code to get it to compile. I made pMsg const so
I could initialize pMsg with a const *. Maybe you could const_cast it
away. (pMsg should be const anyway the way it is being used.)
My point is that the compiler was not creating a copy construct for the
OP's original code. I assume (1) that the compiler does not create the
copy constructor until it is needed, (2) the compiler sees the C-like
initialization of the Msg1, Msg2 instances, and so (3) decides that a
C++ copy constructor should not be used. I'm just guessing.
How do you know that the problem was that it failed to create
the copy ctor? Is that what the error message says? I don't have
that compiler to test.

My point was that without knowing anything but the code posted,
it's a different matter to copy construct a const member than a non
const member. Randall will probably post the error message since
Remy asked for it up thread.
Eliot Frank
2008-06-13 21:14:42 UTC
Permalink
Post by Duane Hebert
How do you know that the problem was that it failed to create
the copy ctor? Is that what the error message says? I don't have
that compiler to test.
My point was that without knowing anything but the code posted,
it's a different matter to copy construct a const member than a non
const member. Randall will probably post the error message since
Remy asked for it up thread.
Yes, that is actually key info. The error message for the original code
(as I copied it to my test bed) was

E2034 Cannot convert 'msgStruct' to 'unsigned int'
E2034 Cannot convert 'msgStruct' to 'unsigned char *'

The intent (as I saw it when I finally understood it) of the original
code was to initialize the array with the data of the initialized
individual data items which would require invocation of a copy ctor.

[ The actual reason that I put any effort into the problem was that I
was initially confused by the syntax and couldn't see how any compiler
(the OP said it worked with gcc and MSC) would accept it at all. ]

The compiler seemed to be trying to initialize the array in a C-like
manner, so I inferred that a copy ctor was not being invoked. The rest
of my post was just speculation as to what the compiler was doing.

-Eliot
Darko Miletic
2008-06-13 19:11:51 UTC
Permalink
Post by Duane Hebert
But his version didn't have pMsg as a const *. Why wouldn't
the compiler be able to create a default copy ctor for a struct
with an int and a char*?
I guess a new issue for QC is discovered.
Eliot Frank
2008-06-13 19:23:56 UTC
Permalink
Post by Duane Hebert
But his version didn't have pMsg as a const *. Why wouldn't
the compiler be able to create a default copy ctor for a struct
with an int and a char*?
It doesn't have anything to do with the const-ness of the member. The
compiler fails to create a default copy ctor if [I am guessing here] it
sees a C-like initialization. The following also compiles (CB2007),

struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
msgStruct(unsigned sz, char const *p):
msgSize(sz), pMsg(const_cast<char *>(p)) {};
};

//struct msgStruct Msg1 = {6,"Hello"};
//struct msgStruct Msg2 = {9,"Good bye"};
struct msgStruct Msg1(6,"Hello");
struct msgStruct Msg2(9,"Good bye");

struct msgStruct MsgArray[] = {
Msg1,
Msg2
};
Randall Parker
2008-06-13 22:18:08 UTC
Permalink
Post by Eliot Frank
It doesn't have anything to do with the const-ness of the member. The
compiler fails to create a default copy ctor if [I am guessing here] it
sees a C-like initialization. The following also compiles (CB2007),
struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
msgSize(sz), pMsg(const_cast<char *>(p)) {};
};
Okay, I copied that copy constructor code into my struct msgStruct and recompiled. But now these two lines of code create problems:

unsigned char ucDiagSessCtrlReqx[2] = {0x10};
struct msgStruct diagSessCtrlReqx = {1, ucDiagSessCtrlReqx};

The second line reports these 4 error messages:
E2034 Cannot convert 'int' to 'msgStruct'
E2291 } expected
E2141 Declaration syntax error
E2190 Unexpected }

Then that set of 4 errors repeats for other pairs of lines where other individual struct msgStruct variables get declared initialized.

Suggestions?

So it seems it is applying the ctor too much?
Post by Eliot Frank
//struct msgStruct Msg1 = {6,"Hello"};
//struct msgStruct Msg2 = {9,"Good bye"};
struct msgStruct Msg1(6,"Hello");
struct msgStruct Msg2(9,"Good bye");
struct msgStruct MsgArray[] = {
Msg1,
Msg2
};
dhoke
2008-06-13 18:47:28 UTC
Permalink
Post by Eliot Frank
Post by Randall Parker
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept.
struct msgStruct Msg1(6,"Hello");
struct msgStruct Msg2(9,"Good bye");
Unfortunately, that would still require them to touch a "large amount of
code" that is declaring the initialized structures as he originally
presented...
Eliot Frank
2008-06-13 19:05:35 UTC
Permalink
Post by dhoke
Post by Eliot Frank
struct msgStruct Msg1(6,"Hello");
struct msgStruct Msg2(9,"Good bye");
Unfortunately, that would still require them to touch a "large amount of
code" that is declaring the initialized structures as he originally
presented...
To quote Dick Cheney, "So?" The code I posted is to me at least
acceptable C++. Maybe the OP's original is too, I don't know. However
the replace function in the editor can do the job.

-Eliot
dhoke
2008-06-13 20:36:40 UTC
Permalink
Post by Eliot Frank
To quote Dick Cheney, "So?"
So, the OP seemed to to me to indicate he didn't want to have to change a
lot of code...

and would also need to verify that his other environments (gcc, vc2003, and
probably 2008) would accept what you wrote (if they are also going to be
using the code base with those environments, since they must be used with at
least one of them already, given that the code already exists.)
Remy Lebeau (TeamB)
2008-06-13 21:23:37 UTC
Permalink
Post by Eliot Frank
It's not creating a copy constructor. You need to add a
constructor to your struct. The following does compile
I don't have CB2007 onhand to test at the moment, but would this type of
copy constructor also work when declaring the array?

struct msgStruct
{
unsigned int msgSize;
unsigned char const *pMsg;

msgStruct(const msgStruct &src): msgSize(src.msgSize),
pMsg(src.pMsg) {};
};



Gambit
Fraser Ross
2008-06-14 20:19:17 UTC
Permalink
msgStruct MsgArray[]= {1, "1", 2, "2"};

Isn't this the syntax you are looking for? There is not a need for a
constructor. For your other question some named constants could be used
inbetween the braces.

Fraser.
Hendrik Schober
2008-06-14 20:42:19 UTC
Permalink
Post by Randall Parker
struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
};
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
and Msg3, 4, etc..
struct msgStruct MsgArray[] = {
Msg1,
Msg2,
etc.....
};
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept. [...]
Well, I get a C2440 here ("cannot convert from 'const char [6]'
to 'unsigned char *'"). If I make pMsg a plain 'char*', it does
indeed compile.

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Fraser Ross
2008-06-15 14:01:06 UTC
Permalink
"Hendrik Schober"> Well, I get a C2440 here ("cannot convert from
'const char [6]'
Post by Hendrik Schober
to 'unsigned char *'"). If I make pMsg a plain 'char*', it does
indeed compile.
Schobi
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.

Fraser.
Hendrik Schober
2008-06-16 08:11:54 UTC
Permalink
Post by Fraser Ross
"Hendrik Schober"> Well, I get a C2440 here ("cannot convert from
'const char [6]'
Post by Hendrik Schober
to 'unsigned char *'"). If I make pMsg a plain 'char*', it does
indeed compile.
Schobi
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
I didn't think so and Comeau is with me on that:

Comeau C/C++ 4.3.10.1 (May 29 2008 09:37:15) for ONLINE_EVALUATION_BETA1
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 6: error: a value of type "const char *" cannot be used to
initialize an entity of type "unsigned char *"
struct msgStruct Msg1 = {6,"Hello"};
^

"ComeauTest.c", line 7: error: a value of type "const char *" cannot be used to
initialize an entity of type "unsigned char *"
struct msgStruct Msg2 = {9,"Good bye"};
^

2 errors detected in the compilation of "ComeauTest.c".
Post by Fraser Ross
Fraser.
Schobi
Fraser Ross
2008-06-16 10:16:59 UTC
Permalink
"Hendrik Schober"
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
I was talking about initialising arrays that I thought was a related
matter. This program demonstrates Borlands compiler bugs with a and b:

int main(int argc, char* argv[])
{
signed char * a= {"1234"};
unsigned char * b= {"234"};
char * c= {"1234"};
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
char c2[]= {"1234"};
return 0;
}


Fraser.
Hendrik Schober
2008-06-16 12:24:16 UTC
Permalink
Post by Fraser Ross
[...]
I was talking about initialising arrays that I thought was a related
int main(int argc, char* argv[])
{
signed char * a= {"1234"};
unsigned char * b= {"234"};
char * c= {"1234"};
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
char c2[]= {"1234"};
return 0;
}
Comeau C/C++ 4.3.10.1 (May 29 2008 09:37:15) for ONLINE_EVALUATION_BETA1
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 3: error: a value of type "const char *" cannot be used to
initialize an entity of type "signed char *"
signed char * a= {"1234"};
^

"ComeauTest.c", line 4: error: a value of type "const char *" cannot be used to
initialize an entity of type "unsigned char *"
unsigned char * b= {"234"};
^
Post by Fraser Ross
Fraser.
Schobi
Chris Uzdavinis (TeamB)
2008-06-16 13:00:36 UTC
Permalink
Post by Fraser Ross
"Hendrik Schober"
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal
can
Post by Fraser Ross
initialise all 3 types of char arrays.
I was talking about initialising arrays that I thought was a related
int main(int argc, char* argv[])
{
signed char * a= {"1234"};
unsigned char * b= {"234"};
char * c= {"1234"};
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
char c2[]= {"1234"};
return 0;
}
What specifically are the bugs with a and b? You talk about arrays in
your description, but are showing code that is using pointers, and
that is not the same thing at all as an array. (Specifically, where
is the memory?)

For an array, the characters can be converted during initialization,
since the array object itslef has the memory, and as such each element
can be converted. However, for pointers they only hold an address and
thus must point to SOMETHING of the right type that lives
elsewhere--but that something doesn't exist since its initializer is
of a different type. The compiler would have to create an additional
unnamed copy/conversion of the data and initialize the pointer to that
unnamed copy's address, but that is NOT how the language works, and
such a pointer initialization is invalid.

FWIW, Comeau agrees that they should not compile:

Comeau C/C++ 4.3.10.1 (May 29 2008 09:37:15) for ONLINE_EVALUATION_BETA1
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 3: error: a value of type "const char *" cannot be used to
initialize an entity of type "signed char *"
signed char * a= {"1234"};
^

"ComeauTest.c", line 4: error: a value of type "const char *" cannot be used to
initialize an entity of type "unsigned char *"
unsigned char * b= {"234"};
^
--
Chris (TeamB);
Chris Uzdavinis (TeamB)
2008-06-16 13:14:55 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
For an array, the characters can be converted during initialization,
since the array object itslef has the memory, and as such each element
can be converted. However, for pointers they only hold an address and
thus must point to SOMETHING of the right type that lives
elsewhere--but that something doesn't exist since its initializer is
of a different type. The compiler would have to create an additional
unnamed copy/conversion of the data and initialize the pointer to that
unnamed copy's address, but that is NOT how the language works, and
such a pointer initialization is invalid.
There is a rule allowing a char* to be initialized with a string
literal, and it doesn't take that much mental effort to apply the same
reasoning to other similar types. I think I made it sound like it's
not possible to implement this, when clearly it is. But I think that
it's chosen to not work because it is working around the type system
and there isn't good justification for doing so.
--
Chris (TeamB);
Fraser Ross
2008-06-16 13:22:47 UTC
Permalink
"Chris Uzdavinis (TeamB)"
Post by Chris Uzdavinis (TeamB)
What specifically are the bugs with a and b? You talk about arrays in
your description, but are showing code that is using pointers, and
that is not the same thing at all as an array. (Specifically, where
is the memory?)
I was demonstrating all types of initialisation of character pointers
and arrays from string literals. The bug is that a and b compile with a
Borland compiler.

Fraser.
Chris Uzdavinis (TeamB)
2008-06-16 16:03:53 UTC
Permalink
Post by Fraser Ross
"Chris Uzdavinis (TeamB)"
Post by Chris Uzdavinis (TeamB)
What specifically are the bugs with a and b? You talk about arrays in
your description, but are showing code that is using pointers, and
that is not the same thing at all as an array. (Specifically, where
is the memory?)
I was demonstrating all types of initialisation of character pointers
and arrays from string literals.
I noticed that...
Post by Fraser Ross
The bug is that a and b compile with a Borland compiler.
But THAT wasn't so clear to me. I thought the lack of compiling was
considered a bug, but you're right... it shouldn't, and if it does is
a bug.
--
Chris (TeamB);
Fraser Ross
2008-06-16 13:40:01 UTC
Permalink
"Chris Uzdavinis (TeamB)"
Post by Chris Uzdavinis (TeamB)
Post by Fraser Ross
I was talking about initialising arrays that I thought was a related
What specifically are the bugs with a and b? You talk about arrays in
your description, but are showing code that is using pointers, and
that is not the same thing at all as an array. (Specifically, where
is the memory?)
You were not following what I said. I spoke about arrays because I
"thought was a related matter". When I said "This program demonstrates
Borlands compiler bugs with a and b" I meant bugs in that there are not
compiler errors.

Fraser.
Fraser Ross
2008-06-22 12:19:08 UTC
Permalink
The QC report number 62104 was about statements such as int* i = "hello
world!";. I've added a comment to it.

Fraser.

Alan Bellingham
2008-06-16 10:56:11 UTC
Permalink
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
Where does it say that?!

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Alan Bellingham
2008-06-16 11:04:57 UTC
Permalink
Post by Alan Bellingham
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
Where does it say that?!
Ah, 8.5.2/1

Which initialises an array, not a pointer. So

signed char * a= {"1234"};
unsigned char * b= {"234"};

are errors, but

signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};

are not. (And Comeau concurs.)

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Hendrik Schober
2008-06-16 12:25:12 UTC
Permalink
Post by Alan Bellingham
Post by Alan Bellingham
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
Where does it say that?!
Ah, 8.5.2/1
Which initialises an array, not a pointer. So
signed char * a= {"1234"};
unsigned char * b= {"234"};
are errors, but
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
are not. (And Comeau concurs.)
Interesting. I didn't know that. Is there a rationale
for this?
Post by Alan Bellingham
Alan Bellingham
Schobi
Alan Bellingham
2008-06-16 12:53:26 UTC
Permalink
Post by Hendrik Schober
Post by Alan Bellingham
Ah, 8.5.2/1
Which initialises an array, not a pointer. So
signed char * a= {"1234"};
unsigned char * b= {"234"};
The underlying types of the literals are array of N (const) char. Not
array of signed char, nor of unsigned char. On assignment, the array may
decay to a pointer (and there's the whole assignment to non-const char*,
too), but it has to decay to be a pointer to the type of the first
element (backward compatibility const allowing).

char, signed char and unsigned char are distinct types in the language,
and you cannot blithely intermix pointers to them.
Post by Hendrik Schober
Post by Alan Bellingham
are errors, but
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
are not. (And Comeau concurs.)
Interesting. I didn't know that. Is there a rationale
for this?
Here, a literal is being used as a shorthand for individual elements, so
signed char a2[]= {"1234"};

is effectively the same as

signed char a2[5]= { '1', '2', '3', '4', '\0' };

and at that point, the individual elements don't express the same
char/signed char/unsigned char specificity. (Though the syntax isn't
extended as far as allowing 'int x[] = { "Hello world" };'.)

I assume that's the reason.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Chris Uzdavinis (TeamB)
2008-06-16 13:13:10 UTC
Permalink
Post by Alan Bellingham
and at that point, the individual elements don't express the same
char/signed char/unsigned char specificity. (Though the syntax isn't
extended as far as allowing 'int x[] = { "Hello world" };'.)
I assume that's the reason.
Also, the only reason that

char * x = "asdf";

works at all, since the types are incompatible, is a loophole designed
solely for backwards compatibilty. Normally the types just don't
work.

When you change char* to something else, it no longer matches the
signature of the loophole.

In revising my previous statement made in a recent post, I think the
compiler is _capable_ of creating a temporary object if necessary, or
of even completely replacing the type of the initializer with one that
is more compatible... if they wanted this construct to work, but
apparently they didn't. The type system not allowing it is a good
think, I think.
--
Chris (TeamB);
Fraser Ross
2008-06-16 13:58:22 UTC
Permalink
"Alan Bellingham"
Post by Alan Bellingham
Here, a literal is being used as a shorthand for individual elements, so
signed char a2[]= {"1234"};
is effectively the same as
signed char a2[5]= { '1', '2', '3', '4', '\0' };
And also

signed char a2[]= { '1', '2', '3', '4', '\0' };

Fraser.
Alan Bellingham
2008-06-16 15:03:41 UTC
Permalink
Post by Fraser Ross
And also
signed char a2[]= { '1', '2', '3', '4', '\0' };
Indeed so. I was showing the ultimate result by including the array
size.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Chris Uzdavinis (TeamB)
2008-06-16 13:02:00 UTC
Permalink
Post by Hendrik Schober
Post by Alan Bellingham
Which initialises an array, not a pointer. So
signed char * a= {"1234"};
unsigned char * b= {"234"};
are errors, but
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
are not. (And Comeau concurs.)
Interesting. I didn't know that. Is there a rationale
for this?
The chars can be converted when going into an array, but for pointers,
the memory is "somewhere else" and there isn't an object of the right
type for it to point to.
--
Chris (TeamB);
Chris Uzdavinis (TeamB)
2008-06-16 13:15:28 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Hendrik Schober
Post by Alan Bellingham
Which initialises an array, not a pointer. So
signed char * a= {"1234"};
unsigned char * b= {"234"};
are errors, but
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
are not. (And Comeau concurs.)
Interesting. I didn't know that. Is there a rationale
for this?
The chars can be converted when going into an array, but for pointers,
the memory is "somewhere else" and there isn't an object of the right
type for it to point to.
... and they didn't want to make an exception to the type system rules
to allow this. (Which is probably a good thing.)
--
Chris (TeamB);
Hendrik Schober
2008-06-19 16:46:34 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Hendrik Schober
Post by Alan Bellingham
Which initialises an array, not a pointer. So
signed char * a= {"1234"};
unsigned char * b= {"234"};
are errors, but
signed char a2[]= {"1234"};
unsigned char b2[]= {"1234"};
are not. (And Comeau concurs.)
Interesting. I didn't know that. Is there a rationale
for this?
The chars can be converted when going into an array, but for pointers,
the memory is "somewhere else" and there isn't an object of the right
type for it to point to.
Thanks to you and Alan for explaining!

Schobi
Chris Uzdavinis (TeamB)
2008-06-19 17:08:39 UTC
Permalink
Post by Hendrik Schober
Post by Chris Uzdavinis (TeamB)
The chars can be converted when going into an array, but for
pointers,
the memory is "somewhere else" and there isn't an object of the right
type for it to point to.
Thanks to you and Alan for explaining!
I'm becomming less and less satisfied with what I said. It sounds
like a poor appeal to implementation details, when in fact, the
compiler could easiy put an object of "the right type" into the
executable, and initialize the pointer to point to that.

unsigned char const * msg = "some message";

Given the above, it's invalid to make an unsigned char pointer point
to an array of const char, but certainly it can point to an array of
unsigned const char. (Since the compiler is building these data
structures in the background, it could make the array be unsigned and
be done with it... we'd never know the difference.)

Therefore, I think the language itself is the reason. The committee
must have made a decision about it, but probaby for a different
reason than what I said. I think I'm going to re-read Alan's post
again. :)
--
Chris (TeamB);
Alan Bellingham
2008-06-19 18:11:04 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Given the above, it's invalid to make an unsigned char pointer point
to an array of const char, but certainly it can point to an array of
unsigned const char. (Since the compiler is building these data
structures in the background, it could make the array be unsigned and
be done with it... we'd never know the difference.)
The problem is with the type of a sting literal. There's the const fudge
already, and I think the committee is rather unwilling to make the
actual type of the literal more vague and unspecified than it already
is.

Frankly, if you want to use strings *as text*, I consider there to be no
reason whatsoever to use anything but pointers to char. [un]signed chars
are different types, and though themselves useful, should not in my
exceedingly arrogant opinion ever be confused with plain char.

[un]signed char types are part of the sequence of [un]signed integer
types. char however exists for textual data. The ability to convert *a*
char to a [un]signed char is useful, especially in conversion routines.
The ability to interchange pointers to them requires reinterpret_cast<>
(or static_cast<> via void*, which is the same thing), and I'm happy for
that to remain the case.

The initialisation of a array of [un]signed char using a string literal
is borderline. Since it doesn't use a pointer to the wrong type
anywhere, it doesn't break the type system any more than the conversion
of a single char to a single [un]signed char.

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Alan Bellingham
2008-06-19 18:12:19 UTC
Permalink
Post by Alan Bellingham
The problem is with the type of a sting literal.
I didn't literally mean 'sting', of course. *cough*

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Randall Parker
2008-06-16 17:43:38 UTC
Permalink
Post by Alan Bellingham
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
Where does it say that?!
So is it possible to initialize an array of structs with whole struct variables?

(the big digression is all very interesting but I would appreciate it if someone could answer my original question)
Chris Uzdavinis (TeamB)
2008-06-16 18:10:21 UTC
Permalink
Post by Randall Parker
Post by Alan Bellingham
Post by Fraser Ross
Is that a Microsoft error code? The language says a string literal can
initialise all 3 types of char arrays.
Where does it say that?!
So is it possible to initialize an array of structs with whole
struct variables?
(the big digression is all very interesting but I would appreciate
it if someone could answer my original question)
It should work. Back to your original code, with minor change, this
is valid:

struct msgStruct {
unsigned int msgSize;
char const * pMsg; // <<<<< changed from unsigned
};

msgStruct msg1 = { 6, "hello" };
msgStruct msg2 = { 7, "world" };

msgStruct MsgArray[] = {
msg1,
msg2
};


This compiles cleanly with g++3.x, g++4.3, and Comeau online.

Does it compile with C++Builder?
--
Chris (TeamB);
Randall Parker
2008-06-16 18:53:10 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
It should work. Back to your original code, with minor change, this
struct msgStruct {
unsigned int msgSize;
char const * pMsg; // <<<<< changed from unsigned
};
msgStruct msg1 = { 6, "hello" };
msgStruct msg2 = { 7, "world" };
msgStruct MsgArray[] = {
msg1,
msg2
};
This compiles cleanly with g++3.x, g++4.3, and Comeau online.
Does it compile with C++Builder?
Short answer: No.

E2034 Cannot convert 'msgStruct' to 'unsigned int'

I tried changing both to signed:

struct msgStruct {
int msgSize; // the number of bytes in the response.
char *pMsg;
};

repeating for every line in the initialized array of structs:

E2034 Cannot convert 'msgStruct' to 'int'
E2034 Cannot convert 'msgStruct' to 'char *'
E2034 Cannot convert 'msgStruct' to 'int'
E2034 Cannot convert 'msgStruct' to 'char *'

(I'm hiding the file name since I need to hide what the program is for)

So signed versus unsigned does not seem to affect this.
Post by Chris Uzdavinis (TeamB)
--
Chris (TeamB);
Eliot Frank
2008-06-16 19:09:50 UTC
Permalink
Post by Randall Parker
So is it possible to initialize an array of structs with whole struct variables?
(the big digression is all very interesting but I would appreciate it if someone could answer my original question)
Yes, I demonstrated it IS possible. See my earliest post in this thread.

-Eliot
Randall Parker
2008-06-16 19:48:11 UTC
Permalink
Post by Eliot Frank
Post by Randall Parker
So is it possible to initialize an array of structs with whole struct variables?
(the big digression is all very interesting but I would appreciate it if someone could answer my original question)
Yes, I demonstrated it IS possible. See my earliest post in this thread.
And I responded to what you said with my report of a different compiler error I got when I tried what you showed.
Post by Eliot Frank
-Eliot
Eliot Frank
2008-06-16 20:23:29 UTC
Permalink
Post by Randall Parker
Post by Eliot Frank
Yes, I demonstrated it IS possible. See my earliest post in this thread.
And I responded to what you said with my report of a different compiler error I got when I tried what you showed.
If you declare a constructor then you can't use C-style initialization:

struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char const *pMsg;

// must declare ctor for both char and unsigned char args
msgStruct(unsigned sz, char const *p):
msgSize(sz), pMsg(p) {};
msgStruct(unsigned sz, unsigned char const *p):
msgSize(sz), pMsg(p) {};
};

struct msgStruct Msg1(6,"Hello");
struct msgStruct Msg2(9,"Good bye");

unsigned char ucDiagSessCtrlReqx[2] = {0x10};
struct msgStruct diagSessCtrlReqx(1, ucDiagSessCtrlReqx); // <--- SEE?

struct msgStruct MsgArray[] = {
Msg1,
Msg2,
diagSessCtrlReqx
};


However here's a variation on the theme that may save some rewriting:

struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char const *pMsg;
};
// Message has a ctor that takes a msgStruct argument
struct Message: msgStruct {
Message(const msgStruct &msg): msgStruct(msg) {};
};

struct msgStruct Msg1 = { 6, "Hello" };
struct msgStruct Msg2 = { 9, "Good bye" };

unsigned char ucDiagSessCtrlReqx[2] = {0x10};
struct msgStruct diagSessCtrlReqx = {1, ucDiagSessCtrlReqx};

struct Message MsgArray[] = { // array of Message instead of msgStruct
Msg1,
Msg2,
diagSessCtrlReqx
};

-Eliot
Fraser Ross
2008-06-17 11:37:12 UTC
Permalink
"Eliot Frank"
Post by Eliot Frank
Post by Randall Parker
So is it possible to initialize an array of structs with whole struct variables?
(the big digression is all very interesting but I would appreciate
it if someone could answer my original question)
Post by Eliot Frank
Yes, I demonstrated it IS possible. See my earliest post in this thread.
-Eliot
You changed a C struct to a C++ class. I think that the simple answer
is no.

Fraser.
Fraser Ross
2008-06-17 13:04:19 UTC
Permalink
With the term C struct I meant a data aggregate not a class with
functions or inheritance etc. I wasn't speaking about the C language.

Fraser.
Duane Hebert
2008-06-17 15:26:24 UTC
Permalink
Post by Fraser Ross
With the term C struct I meant a data aggregate not a class with
functions or inheritance etc. I wasn't speaking about the C language.
I think that you meant a POD struct. There's no problem with
functions and inheritance etc. in a struct.
Fraser Ross
2008-06-17 18:13:04 UTC
Permalink
"Duane Hebert"
Post by Fraser Ross
"Fraser Ross"
Post by Fraser Ross
With the term C struct I meant a data aggregate not a class with
functions or inheritance etc. I wasn't speaking about the C
language.
Post by Fraser Ross
I think that you meant a POD struct. There's no problem with
functions and inheritance etc. in a struct.
A class with a user declared constructor and a POD struct are
initialised differently by a brace enclosed initialiser list.

Fraser.
Duane Hebert
2008-06-18 11:41:42 UTC
Permalink
Post by Fraser Ross
"Duane Hebert"
Post by Fraser Ross
"Fraser Ross"
Post by Fraser Ross
With the term C struct I meant a data aggregate not a class with
functions or inheritance etc. I wasn't speaking about the C
language.
Post by Fraser Ross
I think that you meant a POD struct. There's no problem with
functions and inheritance etc. in a struct.
A class with a user declared constructor and a POD struct are
initialised differently by a brace enclosed initialiser list.
But it's because of the ctor, not the fact that it's a struct. Using
the term "C struct" is confusing because struct is a valid
construct in both languages. If you add a ctor to the struct,
it's no longer POD and it has the same problems with this
sort of initialization.
Fraser Ross
2008-06-18 11:57:30 UTC
Permalink
"Duane Hebert"
Post by Duane Hebert
But it's because of the ctor, not the fact that it's a struct. Using
I have been saying that.
Post by Duane Hebert
the term "C struct" is confusing because struct is a valid
construct in both languages. If you add a ctor to the struct,
it's no longer POD and it has the same problems with this
sort of initialization.
Nobody could think that a C struct has a constructor.

Fraser.
Eliot Frank
2008-06-17 12:56:42 UTC
Permalink
Post by Fraser Ross
You changed a C struct to a C++ class. I think that the simple answer
is no.
Fraser.
(1) The name of this newsgroup is ...language.cpp, not language.c
(2) The initialization of an array with variables is not C syntax. You
need a constructor, either user (explicitly) defined or compiler
(implicitly) defined, which C doesn't have.

You can't do it in C, so I gave a C++ answer in a C++ newsgroup.

-Eliot
Randall Parker
2008-06-16 15:29:43 UTC
Permalink
Post by Hendrik Schober
Post by Randall Parker
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept. [...]
Well, I get a C2440 here ("cannot convert from 'const char [6]'
to 'unsigned char *'"). If I make pMsg a plain 'char*', it does
indeed compile.
Microsoft or CG CB?

You can declare individual initialized structs and then declare and initialize an array of structs with a bunch of struct variables as the entries?

Again, my original problem: I want to declare and initialize some structs that are all of the same type. Then I want to declare and initialize an array of structs.

If you see my June 13 response to Eliot Frank you will see where the problem now is.

Oh, and this should work with CG CB in addition to MS VS and gcc.
Post by Hendrik Schober
Schobi
--
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Hendrik Schober
2008-06-16 19:52:50 UTC
Permalink
Post by Randall Parker
Post by Hendrik Schober
Post by Randall Parker
Well, CG CB 2007 objects to this syntax which gcc and MS VS 2003 happily accept. [...]
Well, I get a C2440 here ("cannot convert from 'const char [6]'
to 'unsigned char *'"). If I make pMsg a plain 'char*', it does
indeed compile.
Microsoft or CG CB?
That was VC7.1.
Post by Randall Parker
You can declare individual initialized structs and then declare
and initialize an array of structs with a bunch of struct
variables as the entries?
I took your posting, removed all the text, and had
the remaining code compiled.
Post by Randall Parker
Again, my original problem: I want to declare and initialize some
structs that are all of the same type. Then I want to declare
and initialize an array of structs.
Yes, I know. I do create such arrays a lot and use
them to initialize maps.
Post by Randall Parker
If you see my June 13 response to Eliot Frank you will see where the problem now is.
It's hard to figure out what you mean this way. From
two postings I pasted together (and modified) the
following:

struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
// msgStruct(unsigned sz, const unsigned char *p)
// : msgSize(sz), pMsg(const_cast<unsigned char *>(p))
// {}
};

unsigned char ucDiagSessCtrlReqx[2] = {0x10};
struct msgStruct diagSessCtrlReqx = {1, ucDiagSessCtrlReqx};

This only compiles (VC8 this time) when I comment out
the ctor, otherwise I get
error C2552: 'diagSessCtrlReqx' : non-aggregates cannot be initialized with initializer list
Post by Randall Parker
Oh, and this should work with CG CB in addition to MS VS and gcc.
Yes, of course.

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Michael
2008-06-15 16:19:55 UTC
Permalink
Isn't tit the same as ...

typedef struct GainEntry_tag
{
double GainValue;
TCHAR GainText[8];
} GainEntry;

GainEntry GainEntries[] =
{
128., TEXT("*128"),
64., TEXT("*64"),
32., TEXT("*32"),
16., TEXT("*16"),
8., TEXT("*8"),
4., TEXT("*4"),
2., TEXT("*2"),
1., TEXT("*1"),
1./2, TEXT("/2"),
1./4, TEXT("/4"),
1./8, TEXT("/8"),
1./16, TEXT("/16"),
1./32, TEXT("/32"),
1./64, TEXT("/64"),
1./128,TEXT("/128"),
1./256,TEXT("/256"),
};


#define N_GAINENTRIES (sizeof(GainEntries) / sizeof (GainEntries[0]))
#define GAIN_DEFAULT_INDEX 9

?

--
Michael


"Randall Parker" wrote in message
Post by Randall Parker
struct msgStruct {
unsigned int msgSize; // the number of bytes in the response.
unsigned char *pMsg;
};
struct msgStruct Msg1 = {6,"Hello"};
struct msgStruct Msg2 = {9,"Good bye"};
and Msg3, 4, etc..
.
Hendrik Schober
2008-06-16 08:22:31 UTC
Permalink
Post by Michael
[...]
#define N_GAINENTRIES (sizeof(GainEntries) / sizeof (GainEntries[0]))
<shudders>

template< typename T, std::size_t N >
inline std::size_t size_of(const (T&)[N]) {return N}
Post by Michael
Michael
Schobi
Thomas Maeder [TeamB]
2008-06-16 15:43:07 UTC
Permalink
Post by Hendrik Schober
Post by Michael
[...]
#define N_GAINENTRIES (sizeof(GainEntries) / sizeof (GainEntries[0]))
<shudders>
template< typename T, std::size_t N >
inline std::size_t size_of(const (T&)[N]) {return N}
In all fairness, it should be said that N_GAINENTRIES is a "compile
time constant" (i.e. can be used as template parameter or for
determining the size of arrays) while the return value of size_of() is
not.


I'd prefer

enum
{
nrGainEntries = sizeof(GainEntries) / sizeof(GainEntries[0])
};

to the macro, though.
Hendrik Schober
2008-06-16 20:03:28 UTC
Permalink
Post by Thomas Maeder [TeamB]
Post by Hendrik Schober
Post by Michael
[...]
#define N_GAINENTRIES (sizeof(GainEntries) / sizeof (GainEntries[0]))
<shudders>
template< typename T, std::size_t N >
inline std::size_t size_of(const (T&)[N]) {return N}
In all fairness, it should be said that N_GAINENTRIES is a "compile
time constant" (i.e. can be used as template parameter or for
determining the size of arrays) while the return value of size_of() is
not.
Yes, I noticed this immediately after I posted...
Post by Thomas Maeder [TeamB]
I'd prefer
enum
{
nrGainEntries = sizeof(GainEntries) / sizeof(GainEntries[0])
};
to the macro, though.
What's wrong with a 'const std::size_t'?

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Chris Uzdavinis (TeamB)
2008-06-16 16:09:44 UTC
Permalink
Post by Hendrik Schober
Post by Michael
[...]
#define N_GAINENTRIES (sizeof(GainEntries) / sizeof
(GainEntries[0]))
<shudders>
template< typename T, std::size_t N >
inline std::size_t size_of(const (T&)[N]) {return N}
As Thomas pointed out, this is a runtime value, not a compile-time
value. However, it can easily be modified to be a compile-time value.

(Remember that post that Alex posted way back when about this? That
was it. Instead of returning a std::size_t, you return an object of a
size equal to N, and then take the sizeof() that object. Wrap that in
a macro, and you have the type-safe version.

In the future C++, a constexpr function may suffice as well.
--
Chris (TeamB);
Hendrik Schober
2008-06-16 20:04:36 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Hendrik Schober
Post by Michael
[...]
#define N_GAINENTRIES (sizeof(GainEntries) / sizeof
(GainEntries[0]))
<shudders>
template< typename T, std::size_t N >
inline std::size_t size_of(const (T&)[N]) {return N}
As Thomas pointed out, this is a runtime value, not a compile-time
value. However, it can easily be modified to be a compile-time value.
(Remember that post that Alex posted way back when about this? [...]
Oh yes, I do. However, I'd have to look up the details
in order to write this.
Post by Chris Uzdavinis (TeamB)
In the future C++, a constexpr function may suffice as well.
What's this?

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Fraser Ross
2008-06-17 11:30:33 UTC
Permalink
"Hendrik Schober"
Post by Fraser Ross
Chris Uzdavinis (TeamB)
Post by Chris Uzdavinis (TeamB)
(Remember that post that Alex posted way back when about this?
[...]
Post by Fraser Ross
Oh yes, I do. However, I'd have to look up the details
in order to write this.
Its in the thread I started called "array syntax".

Fraser.
Fraser Ross
2008-06-17 11:59:26 UTC
Permalink
"Fraser Ross"
Post by Fraser Ross
Its in the thread I started called "array syntax".
Its actually in another thread called "Template problem".

Fraser.
Chris Uzdavinis (TeamB)
2008-06-17 12:37:52 UTC
Permalink
Post by Hendrik Schober
Post by Chris Uzdavinis (TeamB)
In the future C++, a constexpr function may suffice as well.
What's this?
Schobi
It's part of what they call "generalized constant expressions."

Highlights of the new C++ language features are in wikipedia here:
http://en.wikipedia.org/wiki/C%2B%2B0x

A big document, but definately worth the read if you have time and
want a quick intro to what the new C++ may look like. (I think that
people not following the language are in for quite a shock when they
see some of the new syntax! But I digress...)

constexpr is documented here.
http://en.wikipedia.org/wiki/C%2B%2B0x#Generalized_constant_expressions.

One of their examples in a nutshell:

// invalid attempt to create an array of 10 integers in C++
int GetFive() { return 5; }
int array[ GetFive() + 5];

BUT

// valid c++0x: create an array of 10 integers
constexpr int GetFive() { return 5;}
int array[ GetFive() + 5]; // OK
--
Chris (TeamB);
Hendrik Schober
2008-06-19 16:49:30 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Hendrik Schober
Post by Chris Uzdavinis (TeamB)
In the future C++, a constexpr function may suffice as well.
What's this?
[...]
[...]
// valid c++0x: create an array of 10 integers
constexpr int GetFive() { return 5;}
int array[ GetFive() + 5]; // OK
Ah, thanks. That makes sense.

Schobi
Loading...