I encounter some unexpected issues to compile a piece of code and after some time working on it, I think I need assistance. This trim down to a really small minimal exemple. I feel really lost because I am not a total beginner at C, and computer science and general, and for me, not only this should work but it also sound super basic.
#include <string.h>
char* tamere;
tamere=strdup("flute");
Nothing wierd. strdup return a pointer to char. tamere is declared as pointer to char. The compiler is free to allocate on the stack the place for tamere when he see the declaration. Then later, it set it to the result of strdup at definition on line after.
Gcc output
But this basic piece of code fail to compile on my debian machine:
b.c:3:1: warning: data definition has no type or storage class
tamere=strdup("flute");
b.c:3:1: warning: type defaults to ‘int’ in declaration of ‘tamere’ [-Wimplicit-int]
b.c:3:1: error: conflicting types for ‘tamere’
b.c:2:7: note: previous declaration of ‘tamere’ was here
char* tamere;
^~~~~~
b.c:3:8: warning: initialization makes integer from pointer without a cast [-Wint-conversion]
tamere=strdup("flute");
^~~~~~
b.c:3:8: error: initializer element is not constant
So, the question is why? Why this C piece of code is not working. Why the raisonning about compiler seeing the declaration and being able to do is work is wrong? What is the easiest way around?
Gcc version
gcc --version
gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Thanks for your help 🙂
Edit: The current answer explain what is happening. However one could imagine compilers to be a bit smarter, to replace
char* tamere;
tamere = "tata";
(not compiling) into:
char* tamere = "tata";
A even smarter compiler (I tought compilers were smart enought to replace compile time knowed variable (such as 3*2) by there values, would even allow
char* tamere;
tamere=strdup("tata");
Because strdup(“tata”) could be replaced by “tata” (a heap “tata”)
Any reason why this is not a thing, and if you want to separate static variable declaration and definition, you have to write a one time function to setup do the definition?
2
Answers
You cannot execute code outside functions in C. You can only initialize variables declared there to constant expressions. A function call is never a constant expression since it is resolved in run-time.
The historical reason why C is like this, is probably efficiency. All plain variables at file scope have static storage duration and must be initialized before main() is called. Initialized objects through
.data
segment and non (zero) initialized objects through.bss
segment. This variable initialization already consumes start-up overhead.If you would in addition to that also execute functions, the start-up time of the program would become even slower. For example, this is a known performance problem in the C++ language, where objects with static storage duration have their constructors called at start-up.
Furthermore, the function
strdup
isn’t standard C and might not exist insidestring.h
. If you compile the code in strict C mode, this function might turn unavailable since conforming compilers aren’t allowed to declare non-standard functions inside standard headers such asstring.h
. I’d advise to use malloc + strcpy/memcpy instead.You may use only declarations in the file scope but not statements. It is functions that get the control and execute code in C. And the main entry point of a C program is the function
main
.From the C Standard (5.1.2.2.1 Program startup)
The compiler tries to reinterpret this statement
as a declaration with the implied type specifier
int
. And as a result it resumes that the variabletamere
was redeclared with a different type specifier.You could use the expression in the statement as an initializer in the declaration
But the compiler expects a constant expression as an initializer of a variable with the static storage duration. So it again will issue an error.
From the C Standard (6.7.9 Initialization)
So the only acceptable initialization can look like
Otherwise you have to set the value of the pointer in some function for example in main.
Pay attention to that
strdup
is not a standard C function.