skip to Main Content

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


  1. 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 inside string.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 as string.h. I’d advise to use malloc + strcpy/memcpy instead.

    Login or Signup to reply.
  2. 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)

    1 The function called at program startup is named main. The
    implementation declares no prototype for this function. It shall be
    defined with a return type of int and with no parameters:

    int main(void) { /* ... */ }
    

    or with two parameters (referred to here as argc and argv, though any
    names may be used, as they are local to the function in which they are
    declared):

    int main(int argc, char *argv[]) { /* ... */ }
    

    or equivalent;10) or in some other implementation-defined manner

    The compiler tries to reinterpret this statement

    tamere=strdup("flute");
    

    as a declaration with the implied type specifier int. And as a result it resumes that the variable tamere was redeclared with a different type specifier.

    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’
    

    You could use the expression in the statement as an initializer in the declaration

    char * tamere = strdup("flute");
    

    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)

    4 All the expressions in an initializer for an object that has static
    or thread storage duration shall be constant expressions or string
    literals.

    So the only acceptable initialization can look like

    char * tamere = "flute";
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search