前言
程序设计太难了吧……(。_ 。)这篇文章讲了C语言编译地一点东西,但我还不是很懂,之后修改。
一、三个文件是什么关系
如图所示,项目中有三个文件,分别为SeqList.c,SeqList.h和演示.c。
编译开始的时候,首先会编译SeqList.c成为一个dll文件,此时的dll文件类似于一个带接口的包。之后加入SeqList.h进行编译,通过所谓“接口”,SeqList.h起到了一个地图的作用,告诉编译器这些函数代码在哪,从而生成一个演示.c可以引用的库。(大概吧(;′⌒`))
更正补充
1.gcc编译C源码的四个步骤:
预处理->编译->汇编->链接(test.c test.h => test.i => test.s => test.o => test)
1)预处理 gcc -E test.c -o test.i
2)编译 gcc -S test.i -o test.s
3)汇编 gcc -c test.s -o test.o
4)链接 gcc test.o -o test
执行可执行文件test ./test
注:c文件中的#include宏处理,会在预处理的阶段将c中引用的h文件的内容全部写到c文件中,最后生成.i中间文件,这时h 文件中的内容就相当于被写道c文件中。这也为代码的复用提供了渠道,很多的c文件可以去引用同一个h文件,这样这个h文件就会被放到多个c文件中被编译多 次,这也是h文件中不能放定义只能放声明的原因,放定义时被编译多次,在程序链接的时候(系统中定义了多个int a;强符号定义)会出现错误, 声明就不一样,声明表示对定义的扩展,最终都会终结到一个定义上,所以不会出现link时重复定义的错误。
3.多个文件编译在linux下编译:
例如:下面有三个文件,分别是1.cpp 和 2.cpp 和myhead.h 文件。
1.cpp
#include <iostream>
#include "myhead.h"
using namespace std;
int main(){
print();
cout<<"yes !"<<endl;
return 0;
}
2.cpp
#include <iostream>
#include "myhead.h"
using namespace std;
void print(){
std::cout<<" print "<<std::endl;
}
myhead.h
#ifndef __myhead_h
#define __myhead_h
void print();
#endif
假如他们都在一个目录下面,那么编译流程:
g++ -c 2.cpp #将2.cpp 编译成2.o 文件
g++ 1.cpp -o a.out 2.o #多个文件一起链接
#或者
g++ -c 2.cpp
g++ -c 1.cpp
g++ 1.o 2.o -o test
如果没有头文件,两个.c文件编译的。例如:
1.cpp
#include <iostream>
using namespace std;
void fn();
int main(){
cout<<"123"<<endl;
fn();
return 0;
}
2.cpp
#include <iostream>
void fn(){
std::cout<<"fn"<<std::endl;
}
编译
g++ -c 1.cpp
g++ -c 2.cpp
g++ -o test 1.o 2.o
在稍微大一点的项目里面,一般都会包含多个文件。尤其是包含多个头文件,各自头文件的实现,和包含main函数的文件。这样的好处就是更容易开发和维护。例如:
main.cpp 文件是包含main函数的文件,在myinclude的文件下,包含了myhead.h 和 myhead.cpp 文件。分别是头文件的定义和实现。
tree:
main.cpp
#include <iostream>
#include <myhead.h>
using namespace std;
int main(){
//fun_head();
cout<<"in main"<<endl;
int x=100;
int y=200;
cout<<"sum : "<<sum(x,y);
return 0;
}
myhead.h
#ifndef __myhead_h
#define __muhead_h
void print();
int sum(int a,int b);
#endif
myhead.cpp
#include "myhead.h"
#include <iostream>
using namespace std;
void print(){
cout<<"in fun head"<<endl;
}
int sum(int a,int b){
return a+b;
}
这种情况先编译头文件
g++ -c myhead.cpp -o myhead.o
之后直接编译g++ main.cpp 会报错
error: myhead.h: No such file or directory
因为在LINUX下默认搜索头文件及库文件的路径 找不到myhead.h头文件,自己写的头文件不在默认库中,
所以需要-I+头文件路径,
g++ main.cpp -o main -I ../myinclude/ ../myinclude/myhead.o
————————————————
版权声明:本文为CSDN博主「Rani_zZ」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42731241/article/details/108253055
二、预处理的两行代码是什么玩意
#ifndef __SEQLIST_H_INCLUDED_
#define __SEQLIST_H_INCLUDED_
定义宏,并在预处理过程中将其替换为空字符串(即删除)。
这样做主要是为了标记某些内容,使程序阅读者能够清楚标记表明的意义,同时又不影响被编译的源代码。
也就是说,用法同define后接两个参数,只是后一个参数为空字符串。用途包括:
(1)定义一个符号用来给#if(n)def判断。
(2)多文件编译中防止头文件被重复包含。
举个例子,<stdio.h> 里有:
#ifndef __STDIO_H
#define __STDIO_H
比方说你 #include 进来一个 stdio.h ,再 #include 进来一个 string.h 。也许在string.h 头文件里又 include 了 stdio.h。这样你的程序中就 include 了两个 stdio.h。定义了两个 printf 函数等等。这就麻烦了,编译会出错不说,就算编译过了也是浪费资源。
加了一个 #ifndef _STDIO_H 的话。在 #include 进来的 string.h 中如果再试图 include 一遍 stdio.h 的话,由于事先在第一个 stdio.h 中已经定义了 _STDIO_H 这个宏。所以不满足 #ifndef _STDIO_H 这个条件,就不会编译第二次了。
————————————————
版权声明:本段出自CSDN博主「ceci_prayer」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ceci_zhou/article/details/19917637
总结
要去了解一下汇编了,这学期还要学c++,真是令人头秃。