标准库与c中的用户定义头文件(.h)及其实现文件(.c)有何不同?
在main.c中使用标准库与c中的用户定义头文件(.h)及其实现文件(.c)有何不同?,c,static-libraries,header-files,C,Static Libraries,Header Files,在main.c中使用#include包含的libc.a(静态库)等标准库与main.c中包含的用户定义头文件(cube.h)及其在c中的实现文件(cube.c)有何不同 我的意思是两者都是头文件,但一个实现是静态库(.a),另一个实现是源文件(.c) 您可以在cube.c中定义(实现) #include "cube.h" int cube( int x ) { return x * x * x; } 然后我们将把函数声明放在另一个文件中。按照惯例,在本例中,这是在头文件cube.h中完
#include
包含的libc.a(静态库)等标准库与main.c中包含的用户定义头文件(cube.h)及其在c中的实现文件(cube.c)有何不同
我的意思是两者都是头文件,但一个实现是静态库(.a),另一个实现是源文件(.c)
您可以在cube.c中定义(实现)
#include "cube.h"
int cube( int x ) {
return x * x * x;
}
然后我们将把函数声明放在另一个文件中。按照惯例,在本例中,这是在头文件cube.h中完成的
int cube( int x );
现在,我们可以使用#include指令(c预处理器的一部分)从其他地方调用函数,例如main.c
#包括“cube.h”
#包括
int main(){
int c=立方体(10);
printf(“%d”,c);
...
}
另外,如果我在cube.h中包含了include-guards,那么当我在main.c和cube.c中都包含cube.h时会发生什么。它将包括在哪里 编程语言与其实现不同 编程语言是一种规范(写在纸上;您应该阅读,它实际上是C11标准),而不是软件。C标准指定了一个C标准库,并将标题定义为
#include
-d
(你可以在没有任何计算机的情况下,用一堆人类奴隶运行你的C程序;这是非常不道德的;你也可以使用类似于解释器的解释器,避免使用任何编译器、对象或可执行文件)
像libc.a
(静态库)这样的标准库如何使用#include
。。。不同于用户文件cube.c
上面的句子完全错误(毫无意义)libc.a
不#包括
头(即文件/usr/include/stdio.h
和其他内部头,例如/usr/include/bits/stdio2.h
)。当编译main.c
或cube.c
时,就会出现这种包含
原则上,
可能不是计算机上的任何文件(例如,#include
可能会在编译器中触发一些魔法)。实际上,当您#include
时,编译器正在解析/usr/include/stdio.h
(以及其他包含的文件)
一些标准头(特别是
,
,
,…)是由标准指定的,但在编译器的特殊或(即“神奇”东西)帮助下实现
C标准知道
编译器处理(大体上说,实现翻译单元)并从一个阶段(处理和其他指令以及扩展宏)开始。而gcc
不仅运行编译器本身(一些cc1
),而且还运行汇编程序as
和ld
(更多信息,请阅读Levine的书)
出于充分的理由,您的头文件cube.h
实际上应该以开头。在你过于简单的例子中,它们可能是无用的(但你应该养成这个习惯)
您几乎应该始终使用gcc-Wall-Wextra-g
(以获取所有警告和调试信息)。阅读这一章
您还可以将-v
传递给gcc
,以了解实际运行的程序(例如cc1
、ld
、as
)
您可以将-H
传递到gcc
,以了解在预处理阶段包含哪些源文件。您还可以通过gcc-c-eccube.c>cube.i
获得cube.c
的预处理形式的cube.c
作为cube.i
文件,然后使用一些编辑器或寻呼机查看该cube.i
文件
您(或gcc
)需要(在您的示例中)将cube.c
(该文件及其包含的每个头文件给出的翻译单位)编译到cube.o
(假设是Linux系统)中。您还可以将main.c
编译成main.o
。最后,gcc
将链接cube.o
、main.o
、一些启动文件(阅读相关内容)和libc.so
共享库(实现POSIX C标准库规范等)以生成。对象文件、共享(和静态库,如果您使用一些)和可执行文件在Linux上使用文件格式
如果你用几个源文件(和翻译单元)编写一个C程序,你实际上应该使用类似的工具
如果我在cube.h中包含了include-guards,那么当我在main.c和cube.c中都包含cube.h时会发生什么
这应该是两个不同的翻译单元。您可以分几个步骤来编译它们。首先,使用以下命令将main.c
编译为main.o
gcc -Wall -Wextra -g -c main.c
gcc -Wall -Wextra -g -c cube.c
上面的命令正在生成一个main.o
对象文件(借助于cc1
和as
)
然后使用以下命令编译(另一个翻译单元)cube.c
gcc -Wall -Wextra -g -c main.c
gcc -Wall -Wextra -g -c cube.c
因此获得cube.o
(请注意,在cube.h
中添加include-guard不会改变这样一个事实:它将被读取两次,一次是在编译cube.c
时,另一次是在编译main.c
时)
最后,使用
gcc -Wall -Wextra -g cube.o main.o -o yourprog
(我邀请您尝试所有这些命令,并使用gcc-v
而不是上面的gcc
来尝试它们)
请注意,gcc-Wall-Wextra-gcube.cmain.c-oyourprog
正在运行上述所有步骤(使用gcc-v
检查)。您确实应该编写一个脚本来避免键入所有这些命令(只需使用make
进行编译,或者更好地使用make-j
并行运行编译)
最后,您可以使用/y运行可执行文件
% gcc foo.c -Wall -Werror
% ./a.out
2.000000
%
% cat foo.c
#include <math.h>
#include <stdio.h>
int main(void) {
double n;
scanf("%lf\n", &n);
printf("%f\n", sqrt(n));
}
% 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
% 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
int printf(const char * restrict format, ...);
int main(void) {
printf("%f\n", sqrt(4));
}
% 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 ‘<math.h>’ or provide a declaration of ‘sqrt’
% ./a.out
2.000000