Bad connection between `char * array [size]` and `extern char ** array`?

First, look at this example (I did this for an example, this is not a real program):

whatever.h

#ifndef WHATEVER_H #define WHATEVER_H void fill(void); #endif 

main.c

 #include <stdio.h> #include "whatever.h" char *names[10] = {NULL}; int main() { int i; fill(); for (i = 0; i < 10; ++i) printf("%s\n", names[i]); return 0; } 

whatever.c

 #include "whatever.h" extern char **names; void fill(void) { int i; for (i = 0; i < 10; ++i) names[i] = "some name"; } 

When I do this program using:

 gcc -o test main.c whatever.c -Wall -g 

I do not receive any errors or warnings. However, when I run the program, I see that in fill , names are actually NULL . If in whatever.c I change

 extern char **names; 

to

 extern char *names[]; 

then everything will be fine.

Can anyone explain why this is happening? If gcc could not bind extern char **names; with the one that was in main.c , shouldn't it give me an error? If he could bind them, how did it happen that names would be NULL in whatever.c ?

Also, like extern char **names; different from extern char *names[]; ?


I am using gcc version 4.5.1 under Linux.

Update

To continue the research, I change the definition of names in main.c to:

 char *names[10] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; 

(keeping extern char **names; in whatever.c ) and gdb , I see that names matters. If I pass this value to char * and print it, it will give me "1" . (Note that these are not *names , that is, "1" , but (char *)names )

Basically, this means that gcc somehow managed to bind extern char **names; in whatever.c with names[0] in main.c !

+6
source share
1 answer

When you use different, incompatible types for the same variable in different compilation units (as you did here), you get undefined behavior. This means that it probably will not work, and you cannot receive any error or warning messages.

WHY this happens (and why the spec says it's undefined) is explained by how most linkers work. Most linkers do not understand anything about types; they understand only names and memory. As for the linker, the variable is just a block of memory, starting at any address. In your (original) program main.c , names defined as a reference to the beginning of a block of memory large enough to hold 10 pointers (maybe 40 or 80 bytes, depending on whether it is a 32-bit or 64-bit system) all of which are NULL. whaterver.c , on the other hand, assumes that names refers to a block of memory large enough to hold an ONE pointer, and this pointer points to an array of 10 pointers.

+5
source

Source: https://habr.com/ru/post/916928/


All Articles