Recently looking at Apue, is worthy of a classic, see a little harvest a little. But feel some things still not clear, need to do their own verification, the results found that need to use GCC, to understand.
Sometimes, you refer to a function in the code but do not include the relevant header file, this time the GCC error is more bizarre, generally: "MATH.C:6:25: Warning: Implicit declaration and the built-in function ' sin ' is not compatible [by default]". This error on the internet a lot of blogs are saying need to include XXX.h files, but no one explains why this error message is expressed. What is implicit declaration, what is built-in function, I get tangled up.
The concept of the implicit declaration function Online has relevant information, interested students can check their own, here a brief mention. If you call a function a, but GCC cannot find the definition of function A, it will define a function A by default, presumably as follows.
int a (XXX) {return XXX}
Obviously this is not a good thing, because, sometimes GCC will find the problem, prompt this error, if you use such a statement int i = A (XX), so that the GCC will not error, specific behavior I did not go into the study. C language later standards are slowly give up the implicit declaration function, C + + will directly error.
The built-in function , the information about this is relatively small. Finally in the official GCC documents see the relevant introduction, I do not have time to scrutiny just see a few paragraphs, and then combined with some of the words inside the post, presumably to the following speculation:
As the name implies, the built-in function is a function provided by a system or tool that can be used by default. There can be two kinds of understanding, can be the GCC support C language by default let you use these functions, these are gcc-c of the built-in function, and another understanding is gcc specified function, GCC allows you to use these functions. The official documentation says that most of GCC's built-in functions are designed to optimize the code, so I prefer the latter kind of understanding. I think that GCC's built-in functions can be thought of as some of the similar preprocessing functions provided by GCC, which are provided to programmers in the form of C functions, that is to say, C function, in fact, it doesn't matter with C language at last. For example, if there is a direct sin (1) call in the code, then GCC will directly calculate the value of sin (1) and then use this value directly when generating the code, instead of invoking the SIN function with the call sin command. This is called optimization (there are other types of optimizations, this is just one of them).
The official document says that GCC's built-in functions are mainly divided into two categories, one of which is prefixed by _builtin_, and one without prefixes. The latter tends to correspond to a function of a standard library, such as Sin,printf,exit. When the compiler thinks it is possible to optimize the relevant code (as mentioned above directly to derive a result, such as ignoring meaningless computations, etc.), it is directly optimized, and these functions are equivalent to GCC's built-in functions.
The above on the built-in function is also explained, do not know I express clearly no, the following is a few specific examples.
Use the SIN function without connecting LIBM
File:math.c.
#include <stdio.h> #include <math.h> int main () { //int i = 1; printf ("sin (1) =%f.\n", Sin (i)); printf ("sin (1) =%f.\n", sin (1)); return 0;}
This code can be directly gcc math.c-o math.out. Then the./math.out executes directly.
Output: sin (1) =0.841471.
Students accustomed to window programming may feel nothing, but there is a problem with Linux programming. In GCC, include <math.h> this statement simply includes the MATH.H (standard library header file) file in math.c (our example file), but there is only the SIN function declaration in math.h, and there is no definition of the sin function. Normally, using a function declared in math.h, you need to specify the library that implements the function declaration in MATH.H when compiling (exactly the connection), where math.h corresponds to the standard library LIBM.A and libm.so. The former is a static library, and the latter is a dynamic library. You can understand that all the. h files do not need to be compiled (if the include is directly equivalent to inserting into the code), all the. c files need to be compiled. The. h file simply defines the form of a function, regardless of what the function specifically does, For example, the SIN function requires a double parameter, which returns a double value after execution. The students who understand the principles of compilation and compilation should understand that a. c file that invokes the SIN function can be compiled temporarily, regardless of how the SIN function is specifically defined, until the assembly source code is generated. Finally compiled into the assembly source code is probably
Push XXX//parametric press stack
Call Sin
mov xxx xxx or pop xxx//Get return value.
With a function declaration, the compiler knows how to press the argument stack, and knows how to get the return value when it returns.
However, the code will be executed at the end, that is, the generation of the assembly source code is not enough, but also the assembly source code compiled into machine code. At this point, there is no specific code for the SIN function, and the compiler has no way to continue compiling the assembly source code into machine code, only to stay here. The final step in compiling a piece of code is to connect. The connection connects the results of all the specified. c file compilations. As mentioned above, LIBM.A and libm.so implement sin, to be able to run the above code, you need to LIBM.A (this is only used in the static link library) and MATH.C (sample code) compiled results are connected together.
Say a half-day compiler thing, if you do not understand the above content, that estimate will not have to look down, first to add the relevant knowledge to say.
All in all, in GCC if the code uses functions declared in MATH.H, not only include <math.h> in the code, but also specify the connection LIBM.A when compiling. Understanding this, we know why the above example uses "gcc Math.c-o math.out" is very strange. To the point, why this example does not need to connect libm.so.
In the beginning, I thought it was the GCC compiler is intelligent, can automatically identify sin is a function in math.h, and then automatically connect LIBM.A. Or GCC connects to LIBM.A by default, but the data is not found on the Internet. Until you see a post that also asks a similar question, there is an answer to the following: GCC will optimize the code, but the optimization is based on GCC to determine that the optimization is no problem. For example, to replace sin (1) with the true value of sin (1), this is possible, because the code uses SIN (1) for the purpose of 99.9999999% is to calculate the value of sin (1), and this value is determined, then the GCC is compiled at the time of the good, run the time no longer forget. To verify this, you can use the Gcc-s math.c-o MATH.S command to view the assembler source code that GCC compiles math.c (-s Specifies that the compilation behavior stop at the generation assembler source code stage).
1. file"math.c"2 . Section. Rodata3.LC1:4. String"sin (1) =%f.\n"5 . Text6 . Globl Main7 . Type Main, @function8 Main:9.LFB0:Ten . Cfi_startproc One Pushq%RBP A. cfi_def_cfa_offset - -. cfi_offset6, - - - movq%rsp,%RBP the. cfi_def_cfa_register6 -SUBQ $ -,%RSP -MOVABSQ $4605754516372524270,%rax -Movq%rax,-8(%RBP) + Movsd-8(%RBP),%xmm0 - MOVL $. LC1,%edi +MOVL $1,%eax A Pagerprintf atMOVL $0,%eax - Leave -. CFI_DEF_CFA7,8 - ret - . Cfi_endproc -.LFE0: in . Size main,.-main -. ident"GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-4)" to. section. Note. Gnu-stack,"", @progbits
Notice the contents of the main function, where there is only one call printf, and there is no call sin. Also notice that line 17th has an inexplicable number $4605754516372524270. Personally think this is the value of sin (1) After the change of the 8 code. As to what has changed, I also cannot say that this value seems to be not sin (1) The 8 binary of the floating-point result, maybe after some arithmetic, or the result of sin (1) is only part of this 8-binary value, this kind of student can study. In any case, there is no call sin inside the assembly code. It is explained that sin (1) has been optimized.
Also sin (1), under what circumstances does GCC have no way to optimize it? Very simple, int i = 1; Sin (i), so that GCC cannot be optimized. Although it also computes sin (1), GCC only knows how to ask for sin (i) When compiling the code, but he doesn't know what the I value is. Why don't you know? This is the content of the compilation optimization, interested students can understand. Simply put, some variables can be derived from the value in some states, but the current technology can deduce the situation is not much, and need a lot of compilation to deduce, gcc to sin (i) This situation is probably the choice to directly do not deduce.
1#include <stdio.h>2#include <math.h>3 4 intMain () {5 inti =1;6printf"sin (1) =%f.\n", sin (i));7printf"sin (1) =%f.\n", Sin (1));8 return 0;9}
Note that the previous MATH.C code, which removes the comment, is now the MATH.C code. This time, "GCC math.c-o math.out" will be an error:
/TMP/CCYKHBGG.O: In the function ' main ':
MATH.C: (. text+0x15): References not defined for ' sin '
COLLECT2: Error: LD returns 1
Then look at the assembly code, note that this time to the assembly of the code can be generated, only the assembly source program will become machine code, only to find that the sin function of call sin is not defined.
1. file"math.c"2 . Section. Rodata3.LC0:4. String"sin (1) =%f.\n"5 . Text6 . Globl Main7 . Type Main, @function8 Main:9.LFB0:Ten . Cfi_startproc One Pushq%RBP A. cfi_def_cfa_offset - -. cfi_offset6, - - - movq%rsp,%RBP the. cfi_def_cfa_register6 -SUBQ $ +,%RSP -MOVL $1, -4(%RBP) -CVTSI2SD-4(%RBP),%xmm0 + PagerSin - Movsd%XMM0,- -(%RBP) +MOVQ- -(%RBP),%rax AMovq%rax,- -(%RBP) at Movsd- -(%RBP),%xmm0 - MOVL $. LC0,%edi -MOVL $1,%eax - Pagerprintf -MOVABSQ $4605754516372524270,%rax -Movq%rax,- -(%RBP) in Movsd- -(%RBP),%xmm0 - MOVL $. LC0,%edi toMOVL $1,%eax + Pagerprintf -MOVL $0,%eax the Leave *. CFI_DEF_CFA7,8 $ retPanax Notoginseng . Cfi_endproc -.LFE0: the . Size main,.-main +. ident"GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-4)" A. section. Note. Gnu-stack,"", @progbits
There were two call printf at this time, and the first call printf had a "call sin" before it. The second call printf has no call sin in front of it.
In the official GCC document there is a passage to the effect that, for built-in functions, if the code can be optimized, GCC optimizes the code, if not optimized, it is often called directly with the same name as the standard library function. My understanding is that sin (1) optimizes for you, and sin (i) does not optimize, it calls the SIN function declared in math.h.
GCC includes built-in versions of many of the functions in the standard C library. These functions come in both forms:one whose names start __builtin_
with the prefix, and the other without. Both forms has the same type (including prototype), the same address (when their address is taken), and the same meaning As the C library functions even if you specify the -fno-builtin option see C dialect Options). Many of these functions is only optimized in certain cases; If they is isn't optimized in a particular case, a call to the library function is emitted.
The modified descendant code compiles when LIBM.A is available, the specific command is as follows GCC Math.c-lm-o math.out. The-lxxx parameter is to find libxxx.so and LIBXXX.A in the relevant directory. This will allow you to connect to the LIBM.A.
The GCC built-in functions are optional, and we can specify not to use some built-in functions at compile time, gcc-fno-builtin-xxx. Or the first example, using the command: Gcc-fno-builtin-sin math.c-o math.out. This time will be an error, because we specify not to use the built-in sin, that will use the SIN function declared in math.h, while compiling does not specify the connection LIBM.A, this will be an error:
/TMP/CCKY8VEG.O: In the function ' main ':
MATH.C: (. text+0x11): References not defined for ' sin '
COLLECT2: Error: LD returns 1
The initial question , "math.c:6:25: Warning: Implicit declaration is not compatible with the built-in function ' sin ' [enabled by default]" What does it mean? I'm not really sure about this, I just figured out what's called implicit declaration functions and built-in functions. Someone on the forum replied: The built-in function is also prototype, and when the implicit Declaration and the Declaration of the corresponding built-in function are inconsistent, there may be problems, so GCC warns.
What does the last default enable mean? I don't know, presumably using built-in functions.
Finally add an example
1#include <stdio.h>2 //#include <math.h>3 4 intMain () {5 inti =1;6printf"sin (1) =%f.\n", sin (i));7 //printf ("sin (1) =%f.\n", sin (1));8 return 0;9}
When compiling, use Gcc-lm math.c-o math.out. There will be "math.c:6:25: Warning: Implicit declaration is not compatible with the built-in function ' sin ' [enabled by default]" warning, but it can still generate executable files and execute the results correctly. In this example, we do not include math.h, so sin is definitely an implicitly declared function that is incompatible with the built-in function, GCC warns, but because GCC cannot optimize sin (i), it calls the standard library's sin (this call should be built-in, Since we do not contain math.h, GCC should automatically invoke the Sin function in math.c. At the same time the connection was made-LM, the connection was successful. So the resulting executable file calculates sin (1) normally. If the default is enabled by using the implicitly declared function, there should be a problem with the result.
Well, these are my understanding of GCC built-in functions and some speculation, if there is a bad place to say, the students forgive me, if there is said wrong place, welcome to correct.
Understanding of GCC built-in functions and C implicit function declarations and some speculation