[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Is this type of char array initization legal?

DomoChan

10/24/2008 4:22:00 PM

the code below will compile in visual c++ 2003, but im not sure its
valid.

unsigned char myString[200] = "";

after this line executes, all the bytes within myString are indeed set
to '0's' but is this really valid c++ or c? where can I find out how
this is implemented?

Im concerned because I had a 3rd party library wrapper which was
crashing, and I was able to alleviate the crash by changing the
initialization method from the above to ...

unsigned char myString[200];

memset( myString, 0, sizeof( myString ) );

any guidance is greatly appreciated!
-Velik
27 Answers

Victor Bazarov

10/24/2008 4:49:00 PM

0

DomoChan@gmail.com wrote:
> the code below will compile in visual c++ 2003, but im not sure its
> valid.
>
> unsigned char myString[200] = "";
>
> after this line executes, all the bytes within myString are indeed set
> to '0's' but is this really valid c++ or c? where can I find out how
> this is implemented?
>
> Im concerned because I had a 3rd party library wrapper which was
> crashing, and I was able to alleviate the crash by changing the
> initialization method from the above to ...
>
> unsigned char myString[200];
>
> memset( myString, 0, sizeof( myString ) );
>
> any guidance is greatly appreciated!
> -Velik

It is valid. Allowed explicitly by the Standard, subclause 8.5.2.

The only reason it could be crashing is if the compiler wastn't
providing proper initialisation for the array. What you could do is
revert this to what it was and put an assertion to see if it's indeed
the problem:

unsigned char myString[200] = "";
#ifndef NDEBUG
for (int iii = 0; iii < 200; ++iii)
ASSERT(myString[iii] == 0);
#endif

Now, if you are saying that you verified that all elements of the array
are indeed set to 0 after the initialisation, then it's OK, and the
crash is due to some other problem which you just *hid* by introducing
your 'memset' "fix", most likely.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Pete Becker

10/24/2008 4:53:00 PM

0

On 2008-10-24 12:22:09 -0400, DomoChan@gmail.com said:

> the code below will compile in visual c++ 2003, but im not sure its
> valid.
>
> unsigned char myString[200] = "";
>
> after this line executes, all the bytes within myString are indeed set
> to '0's' but is this really valid c++ or c? where can I find out how
> this is implemented?

They're set to zero if myString has static storage duration, and that's
also true with no initializer. If it has automatic storage duration,
myString[0] is set to 0.

>
> Im concerned because I had a 3rd party library wrapper which was
> crashing, and I was able to alleviate the crash by changing the
> initialization method from the above to ...
>
> unsigned char myString[200];
>
> memset( myString, 0, sizeof( myString ) );
>
> any guidance is greatly appreciated!

Apparently the third-party library requires an array with all elements
set to zero. That requirement should be in the documentation for the
library.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Gennaro Prota

10/24/2008 4:56:00 PM

0

DomoChan@gmail.com wrote:
> the code below will compile in visual c++ 2003, but im not sure its
> valid.
>
> unsigned char myString[200] = "";
>
> after this line executes, all the bytes within myString are indeed set
> to '0's' but is this really valid c++ or c? where can I find out how
> this is implemented?
>
> Im concerned because I had a 3rd party library wrapper which was
> crashing, and I was able to alleviate the crash by changing the
> initialization method from the above to ...
>
> unsigned char myString[200];
>
> memset( myString, 0, sizeof( myString ) );
>
> any guidance is greatly appreciated!

Practical advice: change it to

unsigned char myString[ 200 ] = {} ;

What to you mean by "alleviate" the crash?

PS: the language lawyering behind the first initialization is a
bit more complicated than I have time to explain; consider that
the array elements are of type unsigned char (not char) and that
there was a C standard clarification in this area which C++
hasn't picked up (though your C++ compiler might de-facto
implement it).

<http://groups.google.com/group/comp.lang.c++/msg/d5ac14fbe5...

--
Gennaro Prota | name.surname yahoo.com
Breeze C++ (preview): <https://sourceforge.net/projects/b...
Do you need expertise in C++? I'm available.

Pete Becker

10/24/2008 4:59:00 PM

0

On 2008-10-24 12:49:25 -0400, Victor Bazarov <v.Abazarov@comAcast.net> said:

> DomoChan@gmail.com wrote:
>> the code below will compile in visual c++ 2003, but im not sure its
>> valid.
>>
>> unsigned char myString[200] = "";
>>
>> after this line executes, all the bytes within myString are indeed set
>> to '0's' but is this really valid c++ or c? where can I find out how
>> this is implemented?
>>
>> Im concerned because I had a 3rd party library wrapper which was
>> crashing, and I was able to alleviate the crash by changing the
>> initialization method from the above to ...
>>
>> unsigned char myString[200];
>>
>> memset( myString, 0, sizeof( myString ) );
>>
>> any guidance is greatly appreciated!
>
> It is valid. Allowed explicitly by the Standard, subclause 8.5.2.
>
> The only reason it could be crashing is if the compiler wastn't
> providing proper initialisation for the array. What you could do is
> revert this to what it was and put an assertion to see if it's indeed
> the problem:
>
> unsigned char myString[200] = "";
> #ifndef NDEBUG
> for (int iii = 0; iii < 200; ++iii)
> ASSERT(myString[iii] == 0);
> #endif

Hmm, is this required if the char array has automatic storage duration?
I have always assumed that it wasn't, that only the characters
corresponding to characters in the initializer would be initialized,
but it doesn't seem completely clear from a quick glance at the
standard.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Salt_Peter

10/24/2008 5:35:00 PM

0

On Oct 24, 12:22 pm, DomoC...@gmail.com wrote:
> the code below will compile in visual c++ 2003, but im not sure its
> valid.
>
> unsigned char myString[200] = "";
>
> after this line executes, all the bytes within myString are indeed set
> to '0's'  but is this really valid c++ or c?  where can I find out how
> this is implemented?

Sounds like you see the results of a program in debug mode. The string
literal "" is actually {'\0'} so everything after myString[0] has an
undeterminate value. Nobody cares whether some compiler initializes or
not the rest of the array with some magic value, there is no
requirement that says it must.

>
> Im concerned because I had a 3rd party library wrapper which was
> crashing, and I was able to alleviate the crash by changing the
> initialization method from the above to ...
>
> unsigned char myString[200];
>
> memset( myString, 0, sizeof( myString ) );
>
> any guidance is greatly appreciated!
> -Velik

An array has a special initializer that looks like so:
unsigned char myString[200] = {'a'};
which initializes all elements with 'a' in this case.
Note the element type of the array (unsigned char) and the type in the
array init list.
Now having said that, the above is an array, not a terminated sequence
of unsigned characters.

Another reason to prefer modern containers:

#include <vector>

// all elements initialized: guarenteed
std::vector< unsigned char > vuc(200);

// all 'a'
std::vector< unsigned char > vuca(200, 'a');

Pete Becker

10/24/2008 5:41:00 PM

0

On 2008-10-24 13:35:25 -0400, Salt_Peter <pj_hern@yahoo.com> said:

> On Oct 24, 12:22 pm, DomoC...@gmail.com wrote:
>> the code below will compile in visual c++ 2003, but im not sure its
>> valid.
>>
>> unsigned char myString[200] = "";
>>
>> after this line executes, all the bytes within myString are indeed set
>> to '0's'  but is this really valid c++ or c?  where can I find out ho
> w
>> this is implemented?
>
> Sounds like you see the results of a program in debug mode.

In which case, the debug mode needs further thought. Initializing to
all zeros is a bad idea when debugging, because the result looks like
good data.

> The string
> literal "" is actually {'\0'} so everything after myString[0] has an
> undeterminate value. Nobody cares whether some compiler initializes or
> not the rest of the array with some magic value, there is no
> requirement that says it must.
>
>>
>> Im concerned because I had a 3rd party library wrapper which was
>> crashing, and I was able to alleviate the crash by changing the
>> initialization method from the above to ...
>>
>> unsigned char myString[200];
>>
>> memset( myString, 0, sizeof( myString ) );
>>
>> any guidance is greatly appreciated!
>> -Velik
>
> An array has a special initializer that looks like so:
> unsigned char myString[200] = {'a'};
> which initializes all elements with 'a' in this case.

This is just straight aggregate initialization, and it initializes all
values after the end of the initializer to 0, not to the value of the
initializer.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Victor Bazarov

10/24/2008 8:19:00 PM

0

Pete Becker wrote:
> On 2008-10-24 12:49:25 -0400, Victor Bazarov <v.Abazarov@comAcast.net>
> said:
>
>> DomoChan@gmail.com wrote:
>>> the code below will compile in visual c++ 2003, but im not sure its
>>> valid.
>>>
>>> unsigned char myString[200] = "";
>>>
>>> after this line executes, all the bytes within myString are indeed set
>>> to '0's' but is this really valid c++ or c? where can I find out how
>>> this is implemented?
>>>
>>> Im concerned because I had a 3rd party library wrapper which was
>>> crashing, and I was able to alleviate the crash by changing the
>>> initialization method from the above to ...
>>>
>>> unsigned char myString[200];
>>>
>>> memset( myString, 0, sizeof( myString ) );
>>>
>>> any guidance is greatly appreciated!
>>
>> It is valid. Allowed explicitly by the Standard, subclause 8.5.2.
>>
>> The only reason it could be crashing is if the compiler wastn't
>> providing proper initialisation for the array. What you could do is
>> revert this to what it was and put an assertion to see if it's indeed
>> the problem:
>>
>> unsigned char myString[200] = "";
>> #ifndef NDEBUG
>> for (int iii = 0; iii < 200; ++iii)
>> ASSERT(myString[iii] == 0);
>> #endif
>
> Hmm, is this required if the char array has automatic storage duration?
> I have always assumed that it wasn't, that only the characters
> corresponding to characters in the initializer would be initialized, but
> it doesn't seem completely clear from a quick glance at the standard.
>

8.5.1/7:
<<If there are fewer initializers in the list than there are members in
the aggregate, then each member not
explicitly initialized shall be value-initialized (8.5).>>

To me it's pretty clear. Each character from the literal initialises
its respective element of the array. The terminating null character
does initialise the corresponding element of the array *too*. If there
are fewer characters in the literal than elements in the array (which is
an aggregate), the rest of the array elements are zero-initialised.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Default User

10/24/2008 8:30:00 PM

0

Pete Becker wrote:

> On 2008-10-24 12:49:25 -0400, Victor Bazarov
> <v.Abazarov@comAcast.net> said:

> > The only reason it could be crashing is if the compiler wastn't
> > providing proper initialisation for the array. What you could do
> > is revert this to what it was and put an assertion to see if it's
> > indeed the problem:
> >
> > unsigned char myString[200] = "";
> > #ifndef NDEBUG
> > for (int iii = 0; iii < 200; ++iii)
> > ASSERT(myString[iii] == 0);
> > #endif
>
> Hmm, is this required if the char array has automatic storage
> duration? I have always assumed that it wasn't, that only the
> characters corresponding to characters in the initializer would be
> initialized, but it doesn't seem completely clear from a quick glance
> at the standard.

Interesting. I also didn't find anything explicit regarding string
literals, just the usual "fewer initializer" rule:

If there are fewer initializers in the list than there are
members in the aggregate, then each member not explicitly
initialized shall be value-initialized (8.5).

The C standard does contain such wording (assuming that it didn't
change from the draft standard):

[#21] If there are fewer initializers in a brace-enclosed
list than there are elements or members of an aggregate, or
fewer characters in a string literal used to initialize an
array of known size than there are elements in the array,
the remainder of the aggregate shall be initialized
implicitly the same as objects that have static storage
duration.

C89's wording was similar to the C++ standard, but had further examples
to show that initialization with a string literal is identical to a
brace-enclosed list of the characters, which would amount to the same
thing.




Brian

Pete Becker

10/24/2008 8:47:00 PM

0

On 2008-10-24 16:18:56 -0400, Victor Bazarov <v.Abazarov@comAcast.net> said:

> Pete Becker wrote:
>> On 2008-10-24 12:49:25 -0400, Victor Bazarov <v.Abazarov@comAcast.net> said:
>>
>>> DomoChan@gmail.com wrote:
>>>> the code below will compile in visual c++ 2003, but im not sure its
>>>> valid.
>>>>
>>>> unsigned char myString[200] = "";
>>>>
>>>> after this line executes, all the bytes within myString are indeed set
>>>> to '0's' but is this really valid c++ or c? where can I find out how
>>>> this is implemented?
>>>>
>>>> Im concerned because I had a 3rd party library wrapper which was
>>>> crashing, and I was able to alleviate the crash by changing the
>>>> initialization method from the above to ...
>>>>
>>>> unsigned char myString[200];
>>>>
>>>> memset( myString, 0, sizeof( myString ) );
>>>>
>>>> any guidance is greatly appreciated!
>>>
>>> It is valid. Allowed explicitly by the Standard, subclause 8.5.2.
>>>
>>> The only reason it could be crashing is if the compiler wastn't
>>> providing proper initialisation for the array. What you could do is
>>> revert this to what it was and put an assertion to see if it's indeed
>>> the problem:
>>>
>>> unsigned char myString[200] = "";
>>> #ifndef NDEBUG
>>> for (int iii = 0; iii < 200; ++iii)
>>> ASSERT(myString[iii] == 0);
>>> #endif
>>
>> Hmm, is this required if the char array has automatic storage duration?
>> I have always assumed that it wasn't, that only the characters
>> corresponding to characters in the initializer would be initialized,
>> but it doesn't seem completely clear from a quick glance at the
>> standard.
>>
>
> 8.5.1/7:
> <<If there are fewer initializers in the list than there are members in
> the aggregate, then each member not
> explicitly initialized shall be value-initialized (8.5).>>

Well, yes, that's the requirement for aggregate initialization. But
does aggregate initialization apply here? Aggregate initialization is
indicated by "a brace-enclosed, comma-separated list ...", which isn't
present here. I don't see anything in 8.5.2 [dcl.init.string] that says
that aggregate initialization is used, although the "optionally
enclosed in braces" hints that it may be.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Pete Becker

10/24/2008 8:50:00 PM

0

On 2008-10-24 16:29:45 -0400, "Default User" <defaultuserbr@yahoo.com> said:

> Pete Becker wrote:
>
>> On 2008-10-24 12:49:25 -0400, Victor Bazarov
>> <v.Abazarov@comAcast.net> said:
>
>>> The only reason it could be crashing is if the compiler wastn't
>>> providing proper initialisation for the array. What you could do
>>> is revert this to what it was and put an assertion to see if it's
>>> indeed the problem:
>>>
>>> unsigned char myString[200] = "";
>>> #ifndef NDEBUG
>>> for (int iii = 0; iii < 200; ++iii)
>>> ASSERT(myString[iii] == 0);
>>> #endif
>>
>> Hmm, is this required if the char array has automatic storage
>> duration? I have always assumed that it wasn't, that only the
>> characters corresponding to characters in the initializer would be
>> initialized, but it doesn't seem completely clear from a quick glance
>> at the standard.
>
> Interesting. I also didn't find anything explicit regarding string
> literals, just the usual "fewer initializer" rule:
>
> If there are fewer initializers in the list than there are
> members in the aggregate, then each member not explicitly
> initialized shall be value-initialized (8.5).
>
> The C standard does contain such wording (assuming that it didn't
> change from the draft standard):
>
> [#21] If there are fewer initializers in a brace-enclosed
> list than there are elements or members of an aggregate, or
> fewer characters in a string literal used to initialize an
> array of known size than there are elements in the array,
> the remainder of the aggregate shall be initialized
> implicitly the same as objects that have static storage
> duration.
>
> C89's wording was similar to the C++ standard, but had further examples
> to show that initialization with a string literal is identical to a
> brace-enclosed list of the characters, which would amount to the same
> thing.
>

So C99 made it crystal clear, presumably because C90 wasn't. <g>

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)