项目编译的过程和#define后接一个参数的情况

本文介绍了C语言编译的四个步骤:预处理、编译、汇编和链接,以及头文件在多文件编译中的作用。通过预处理避免头文件重复包含,保证代码正确链接。同时,文章探讨了gcc编译命令的使用,展示了如何在Linux环境下编译多个源文件。
摘要由CSDN通过智能技术生成


前言

程序设计太难了吧……(。_ 。)这篇文章讲了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++,真是令人头秃。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值