How a standard library differ from user defined header file (.h) and its implementation file (.c) in C?

后端 未结 2 1750
旧时难觅i
旧时难觅i 2021-01-28 12:12

How a standard library like libc.a (static library) which is included using #include in our main.c differ from user defined header file (cube.h) inc

2条回答
  •  粉色の甜心
    2021-01-28 13:00

    TL;DR: the most crucial difference between the C standard library and your library function is that the compiler might intimately know what the standard library functions do without seeing their definition.


    First of all, there are 2 kinds of libraries:

    1. The C standard library (and possibly other libraries that are part of the C implementation, like libgcc)

    2. Any other libraries - which includes all those other libraries in /usr/lib, /lib, etc.., or those in your project.

    The most crucial difference between a library in category 1 and a library in category 2 library is that the compiler is allowed to assume that every single identifier that you use from category 1 library behaves as if it is the standard library function and behaves as if in the standard and can use this fact to optimize things as it sees fit - this even without it actually linking against the relevant routine from the standard library, or executing it at the runtime. Look at this example:

    % cat foo.c 
    #include 
    #include 
    
    int main(void) {
        printf("%f\n", sqrt(4.0));
    }
    

    We compile it, and run:

    % gcc foo.c -Wall -Werror
    % ./a.out 
    2.000000
    %
    

    and correct result is printed out.

    So what happens when we ask the user for the number:

    % cat foo.c 
    #include 
    #include 
    
    int main(void) {
        double n;
        scanf("%lf\n", &n);
        printf("%f\n", sqrt(n));
    }
    

    then we compile the program:

    % gcc foo.c -Wall -Werror
    /tmp/ccTipZ5Q.o: In function `main':
    foo.c:(.text+0x3d): undefined reference to `sqrt'
    collect2: error: ld returned 1 exit status
    

    Surprise, it doesn't link. That is because sqrt is in the math library -lm and you need to link against it to get the definition. But how did it work in the first place? Because the C compiler is free to assume that any function from standard library behaves as if it was as written in the standard, so it can optimize all invocations to it out; this even when we weren't using any -O switches.


    Notice that it isn't even necessary to include the header. C11 7.1.4p2 allows this:

    Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.

    Therefore in the following program, the compiler can still assume that the sqrt is the one from the standard library, and the behaviour here is still conforming:

    % cat foo.c
    int printf(const char * restrict format, ...);
    double sqrt(double x);
    
    int main(void) {
        printf("%f\n", sqrt(4.0));
    }
    % gcc foo.c -std=c11 -pedantic -Wall -Werror
    % ./a.out
    2.000000
    

    If you drop the prototype for sqrt, and compile the program,

    int printf(const char * restrict format, ...);
    
    int main(void) {
        printf("%f\n", sqrt(4));
    }
    

    A conforming C99, C11 compiler must diagnose constraint violation for implicit function declaration. The program is now an invalid program, but it still compiles (the C standard allows that too). GCC still calculates sqrt(4) at compilation time. Notice that we use int here instead of double, so it wouldn't even work at runtime without proper declaration for an ordinary function because without prototype the compiler wouldn't know that the argument must be double and not the int that was passed in (without a prototype, the compiler doesn't know that the int must be converted to a double). But it still works.

    % gcc foo.c -std=c11 -pedantic
    foo.c: In function ‘main’:
    foo.c:4:20: warning: implicit declaration of function ‘sqrt’
                 [-Wimplicit-function-declaration]
         printf("%f\n", sqrt(4));
                        ^~~~
    foo.c:4:20: warning: incompatible implicit declaration of built-in function ‘sqrt’
    foo.c:4:20: note: include ‘’ or provide a declaration of ‘sqrt’
    % ./a.out
    2.000000
    

    This is because an implicit function declaration is one with external linkage, and C standard says this (C11 7.1.3):

    [...] All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage. [...]

    and Appendix J.2. explicitly lists as undefined behaviour:

    [...] The program declares or defines a reserved identifier, other than as allowed by 7.1.4 (7.1.3).

    I.e. if the program did actually have its own sqrt then the behaviour is simply undefined, because the compiler can assume that the sqrt is the standard-conforming one.

提交回复
热议问题