C- static initialization of structures


 
Thread Tools Search this Thread
Top Forums Programming C- static initialization of structures
# 1  
Old 12-15-2012
Question C- static initialization of structures

Situation:
I have an array of structures:
Code:
    struct my_struct_type {
        char tags_sn[5];
        char group_c;
        char is_err_c;
    };
    struct my_struct_type stuff[] = {
        "abcd", 'A', 'E',
        "efgh", 'B', 'E',
        "ijkl", 'C', 'E'
        NULL, '\0', '\0'
    };

This compiles under gcc.
Code:
% gcc -v
Using built-in specs.
Target: hppa2.0w-hp-hpux11.23
Configured with: ../gcc/configure
Thread model: posix
gcc version 4.2.3
% uname -a
HP-UX warthog B.11.23 U 9000/800 1173444606 unlimited-user license

In a loop that uses tags_sn == NULL as its terminating condition, it fails to terminate and instead of course gets a segmentation violation and dumps core. After pulling out of hair for a while, I realize that I have just initialized an array (constant address) with NULL. But wait! Why does the compiler allow me to say (essentially) tags_sn = NULL;? You can't just assign an integer, or even an integer cast as a pointer, to an array, can you? An array is a constant address. You can't assign to a constant; it's constant!

Why does this compile?

I've been programming in C professionally since 1984. My dog-eared K&R says trying to assign to an array address is a no-no.

Changing the structure declaration to char *tags_sn; makes everything happy. This is clearly my error, but isn't the compiler supposed to catch dumb errors like this?

Final question: when the (implied) code char tags_sn[5]; tags_sn = NULL; compiles, what does it do?
# 2  
Old 12-15-2012
It probably would have complained about assigning a pointer to an array if you'd been doing so. You overran the end of the structure, and that data was probably truncated.

You forgot outer brackets. You probably got a warning about the overflow.

Code:
    struct my_struct_type stuff[] = {
       { "abcd", 'A', 'E' } ,
       { "efgh", 'B', 'E' } ,
       { "ijkl", 'C', 'E', } ,
       { NULL, '\0', '\0', } ,
    };

# 3  
Old 12-15-2012
Code:
   struct my_struct_type {
        char tags_sn[5];
        char group_c;
        char is_err_c;
    };
    struct my_struct_type stuff[] = {
        {"abcd", 'A', 'E'},
        {"efgh", 'B', 'E'},
        {"ijkl", 'C', 'E'},
        { '\0', '\0', '\0'}
    };

This compiles and runs:

Code:
#include <stdlib.h>
   struct my_struct_type {
        char tags_sn[5];
        char group_c;
        char is_err_c;
    };
    struct my_struct_type stuff[] = {
        {"abcd", 'A', 'E'},
        {"efgh", 'B', 'E'},
        {"ijkl", 'C', 'E'},
        { '\0', '\0', '\0'}
    };
    
int main()
{
	 int i=0;
	 for(i=0; stuff[i].is_err_c; i++)
	    printf("%d\n", i);
	 return 0;   
}

output:
Code:
$ ./a.out
0
1
2

This works to compile and find some errors you had:

Code:
gcc -Wall stuff.c

If you are going to use an ancient standard you should also tell the compiler

Code:
gcc -std=c89  -Wall -pedantic somefile.c

# 4  
Old 12-15-2012
Thanks for your input, Jim (quoted below).

Things to note: my understanding was that each comma-separated initializer was taken to be THE data for EACH individual structure member, not just converted to a string of bytes that get mapped into the bytes of the structure, which is what you seem to imply.

No, got no warnings about overflow. The data printed off while the loop I referenced was precisely in synch with the expectations I had, until it ran off the end of the loop because the value of tags_sn was not (and could never be) "NULL". Changing tags_sn from array to pointer DID allow tags_sn to then assume the value of "NULL".

Your point about using additional brackets is excellent (DOH!) but does not address the actual problem.

Your test loop did not use tags_sn's value to terminate the loop. You used the less equivocal is_err_c, so again, what did the compiler do with the NULL initializer?

Obviously it is doing what it thinks I told it, but I am not sure what that was.

A hint has come to me (not in this forum), that APPARENTLY, in the C99 standard (tres nouveaux!) there is a doomiflobby that says you can initialize a sub-array or some such simply by waving a single value at it, and it will automagically interpret the flexure of one's wrist to determine that that value is to be used to fill the implicitly uninitialized portion of the array. And that under this apparent relaxation of K&R, my tags_sn[5] array was initialized with 5 null bytes ('\0'), derived from the 32-bit integer (value=zero) that had been cast as a pointer to void.

I suppose it could be argued that a zero is a zero, and that the rules allow the compiler to promote datatypes as needed. I would understand this behavior if I had initialized the array with an empty string "", where I would expect, because this is static, for the uninitialized bytes to be set to '\0's, and the sole component of the "", a single '\0', to fill tags_sn[0].

But with a pointer to void, is this the right thing to do?

(I'm debating myself at this point, @jimmacnamara did not way anything about this) Since (void *)0 is a void pointer, it can be assigned to any pointer. But the array tags_sn[5] is not a pointer, at least not an assignable one (being a constant); it is a series of 8-bit integers, with tags_sn symbolizing the address of the first one. Since tags_sn = "heck"; works, so should tags_sn = (void *)0;? "heck" points to constant bytes in the initialized data segment. (void *) points to nothing. How can the compiler decide that *((void *)0) is '\0'? How is that analogous to *("heck") == 'h'?

There may be other plausible explanations for the compiler's decision making. It would be interesting to know from an internals perspective what the process is that led the compiler to do what it did.

I think now, after musing on this more, and after seeing the reply, that the compiler mostly did what it should, based on the "heck" analogy. But I still wonder about it leaping from there to say that *((void *)0) is '\0'. Or maybe my reasoning is faulty even there.

Quote:
Originally Posted by jim mcnamara
Code:
   struct my_struct_type {
        char tags_sn[5];
        char group_c;
        char is_err_c;
    };
    struct my_struct_type stuff[] = {
        {"abcd", 'A', 'E'},
        {"efgh", 'B', 'E'},
        {"ijkl", 'C', 'E'},
        { '\0', '\0', '\0'}
    };

This compiles and runs:

Code:
#include <stdlib.h>
   struct my_struct_type {
        char tags_sn[5];
        char group_c;
        char is_err_c;
    };
    struct my_struct_type stuff[] = {
        {"abcd", 'A', 'E'},
        {"efgh", 'B', 'E'},
        {"ijkl", 'C', 'E'},
        { '\0', '\0', '\0'}
    };
    
int main()
{
     int i=0;
     for(i=0; stuff[i].is_err_c; i++)
        printf("%d\n", i);
     return 0;   
}

output:
Code:
$ ./a.out
0
1
2

This works to compile and find some errors you had:

Code:
gcc -Wall stuff.c

If you are going to use an ancient standard you should also tell the compiler

Code:
gcc -std=c89  -Wall -pedantic somefile.c

---------- Post updated at 06:45 PM ---------- Previous update was at 06:37 PM ----------

forgot to say, the compiler options used at my company are:

Code:
gcc -fdollars-in-identifiers -g -DHP_UX -march=1.0 -DHPUX

No doubt that there are multitudinous options we could use, including -c89, though the shop's tendency is to favor c94 (the non-existent intermediate standard hovering somewhere between c89 and c99), and my personally dinosaurian favored standard is C72 as embodied in K&R.

---------- Post updated at 06:49 PM ---------- Previous update was at 06:45 PM ----------

also forgot to thank Corona688 for his reply regarding the possibility of overflow. As stated above, the data displayed from the debug printfs in the loop that processes this array showed the data in synch with the initializers as implied. The actual structure went on with several more members, including several other character pointers; their values were all as expected. The outer brackets are helpful but not required, as demonstrated by the fact that the data aligned as expected.
# 5  
Old 12-15-2012
It put it in memory, sure, but being beyond the bounds of the single structure, would it have been able to check its type? That it aligned despite you not putting in the inner { } properly isn't something I would trust.

This is C, after all. compiles doesn't necessarily mean the code does what you intended.

Last edited by Corona688; 12-16-2012 at 12:06 AM..
# 6  
Old 12-16-2012
As I pointed out in my reply to @jimmacnamara, there was no overflow. By means of logic that is not obvious to me, the compiler made certain decisions, which resulted in two things:

1. The data aligned, one comma-separated datum per named member of each instance of the structure within the array of structures. The values expected, except for the NULL-initialized char [5], appeared in their expected places in the array and within every element of the array. If they didn't align one to one, that would have been the time to break out the additional curly braces.

2. The "NULL" initializer of the member array was interpreted as a signal to initialize the member array with null bytes. Somehow, no doubt through application of fundamental rules of the language (which is what is not clear to me), the compiler made the decision to convert the *((void *)0) to (char)0, essentially converting a declared pointer into a declared integer.

To my knowledge there is not a simpler explanation of the decision (the need for that decision that I created by expecting the compiler to resolve ambiguous code notwithstanding) than to ascribe it to datatype promotion/demotion. Typically, though, the compiler balks at pointer-integer conversion, and I would have expected something like that here, rather than silently do as it thought I said.

I think there should have been a warning somewhere, or an error, applied to the construct by the compiler. But alas, none was indicated.

I am aware that the compiler "tries" to do what it asked to do, and to try to make things fit, but if it's not clear, I'd rather have errors and warnings out the kazoo than to have it guess as to what is intended. And I know that the compiler is neither intelligent nor animate, and can only obey the rules given; I am at this point really only interested in understanding the rules that came into play here.
# 7  
Old 12-16-2012
No.

Code:
Since tags_sn = "heck"; works, so should tags_sn = (void *)0;

tags_sn is properly initialized with '\0', or {0x0}; not NULL
Code:
(void *)0.

Why? the standard says that tags_sn is an array. Valid ways to initialize an array of char all NUL is to use the { } construct or a zero. In either case the first element of the array is set to what is inside { } or to zero, all successive bytes are set to zero.


Code:
   struct my_struct_type {
        char tags_sn[5];
        char group_c;
        char is_err_c;
    };
    struct my_struct_type stuff[] = {
        {"abcd", 'A', 'E'},
        {"efgh", 'B', 'E'},
        {"ijkl", 'C', 'E'},
        { {0x0}, '\0', '\0'}
    };
    
int main()
{
	 int i=0;
	 for(i=0; *stuff[i].tags_sn; i++)  
	    printf("%d\n", i);
	 return 0;   
}

Note the red changes, this code ran identically to the first corrected version.
Code:
$ ./a.out
0
1
2

An array declaration is not a pointer, nor is an array a pointer. A reference to an array is a pointer. That is why the *stuff thing works,
but assigning NULL to an array does not work correctly. In K & R a zero is the equivalent of a NULL in a pointer context. The NULL as well as void -- came later. This (char *)0 construct made a NULL in K & R, and its use carried forward. There was no void to start with.

Last edited by jim mcnamara; 12-16-2012 at 02:14 AM..
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Error occurred during initialization of VM

Hi , I was invoking a sh file using the nohup command. But while invoking, I received a below error. Error occurred during initialization of VM Unable to load native library: /u01/libjava.so: cannot open shared object file: No such file or directory . Could you please help out. Regards,... (2 Replies)
Discussion started by: Kamal1108
2 Replies

2. Shell Programming and Scripting

Variable initialization

Hallo Team, I have a simple request and i would appreciate your help. I would like to use two dates in my script lets: A=$(date +"%d %B %Y") echo $A 23 June 2014 That's awesome now we cooking. Now i want B to be on the previous month eg: echo $B Should give me 23 May 2014 I would... (9 Replies)
Discussion started by: kekanap
9 Replies

3. Shell Programming and Scripting

Initialization error

new to shell scripting. below line is showing error in script. ${parameter:=word} in the o/p first it shows the below error. word: not found. and then in next line print "word" ---------------- p2: word: not found. word --------------------------- OS is AIX and shell is... (12 Replies)
Discussion started by: scriptor
12 Replies

4. Programming

Even the Static cURL Library Isn't Static

I'm writing a program which uses curl to be run on Linux PCs which will be used by a number of different users. I cannot make the users all install curl on their individual machines, so I have tried to link curl in statically, rather than using libcurl.so. I downloaded the source and created a... (8 Replies)
Discussion started by: BrandonShw
8 Replies

5. Programming

Class Pointer initialization C++

Hello everyone, I have a question, that are the following ways of pointer intialization same ? ClassA *point; point = 0; point = new ClassA; Thanks a load in advance!! Regards, (10 Replies)
Discussion started by: mind@work
10 Replies

6. Shell Programming and Scripting

little confusion about variable initialization.

Whenever i execute the below scriptlet with out proper file name it deletes /tmp directory . I guess this is because value of variable a didnt get initialized and there for rm -rf /tmp/ get executed and entire /tmp directory get deleted. How would i avoid any empty variables to be used in... (9 Replies)
Discussion started by: pinga123
9 Replies

7. IP Networking

I need HELP to Set up Coyote Linux router with 1 static IP & 64 internal static IP

hello, i need help on setting my coyote linux, i've working on this for last 5 days, can't get it to work. I've been posting this message to coyote forum, and other linux forum, but haven't get any answer yet. Hope someone here can help me...... please see my attached picture first. ... (0 Replies)
Discussion started by: dlwoaud
0 Replies

8. Programming

Char initialization

Hi All, char a="\0"; a) a contains \0 a contains garbage value b) a contains \ a contains 0 a contains garbage value Pls, let me know correct result is a or b. I guess a. Thanks, Naga:cool: (2 Replies)
Discussion started by: Nagapandi
2 Replies

9. UNIX for Dummies Questions & Answers

Shell initialization files

As you know, when a user logs in, the shell reads the initialization files in an order something like below... ################### Bourne Shell /etc/profile > $HOME/.profile Bash Shell /etc/profile > $HOME/.bash_profile > $HOME/.bash_login > $HOME/.profile > $HOME/.bashrc C Shell... (3 Replies)
Discussion started by: SeanWuzHere
3 Replies

10. Programming

Struct Initialization

Hi We are using a code generator for initializing structures with the #define macro. Compiling it with the GCC 2.8.1 (with -ansi) it OK. But when we are using the SUN C 5.0 compiler it screams. Following is a code sample: #include <stdlib.h> #include <stdio.h> typedef struct TEST3 {... (4 Replies)
Discussion started by: amatsaka
4 Replies
Login or Register to Ask a Question