概述

对于刚接触C语言的同学来说,通常对“在文件中用#include预处理操作符引入文件”和“编译时链接多个文件”这两个操作会有所混淆,这个文章主要为了解析一下它们的区别。

#include预处理操作符

对于此类操作,你可以在C语言预处理机制上去理解,预处理,顾名思义是编辑器在编译前进行的一系列操作,例如把预定义常量替换成字面量等等,具体可以去参考一下编译器对#define操作符的处理过程。

对于#include,实际上可以理解成PHP的include(如果你是先学PHP,再学C的同学),它实际上只是把文件引用进来,被引用文件被视为引用文件的一部分,文件作用域适用于这个文件

1.在文件a.h中声明了一个变量,a.h被b.c引用进来,这时a.h相当于b.c的一部分,所以b.c具备了a.h声明的变量

a.h:

int foo = ;

b.h

#include <stdio.h>
#include "a.h"int main(void)
{
printf("%d\n", foo);//输出1024
}

用编译器直接编译b.h,无需链接a.h,因为a.h已经被引入了:

gcc -std=gnu99   b.c -o b

2.为了证明被引入的文件会被视为跟引入文件一体这个事实,再用下面这个示例说明一下,b.c引入头文件a.h,a.h包含一个static变量,c.c包含试图访问a.h的变量的代码,但是c.c不引入a.h,而是编译时跟b.c链接:

我们先来看看正确的示范,首先不把foo声明为static编译程序,此时实际上是b.c和c.c相链(b.c包含了a.h)

a.h:

int foo = ;

b.h:

#include <stdio.h>
#include "a.h" extern void test(void);
int main(void)
{
printf("b:foo:%d\n", foo);
//test in c.c
test();
}

c.c

#include <stdio.h>

extern int foo;
void test(void)
{
printf("c:foo:%d\n", foo);
}

编译程序:

gcc -std=gnu99  b.c c.c -o b

运行输出:

b:foo:
c:foo:

再来看看把头文件变量声明为static后的影响,此时把foo声明为static:

static int foo = ;

再次编译可见发现报错:

# gcc -std=gnu99 -trigraphs  b.c c.c -o b
/tmp/cc8ojf4Q.o: In function `test':
c.c:(.text+0x6): undefined reference to `foo'
collect2: error: ld returned exit status

这是因为static具有文件作用域,b.c和c.c不视为同一个文件,而a.h和b.c则视为同一个文件;

可以看看以下示例,更进一步说明了这一点,a.h声明的常量又或者变量,都可以在b.c访问到,通过链接形式的c.c访问foo和BAR则不行:

a.h:

#define BAR 256
static int foo = ;

b.h:

#include <stdio.h>
#include "a.h" int main(void)
{
printf("b:bar:%d\n", BAR);//输出256
printf("b:foo:%d\n", foo);//输出1024
}

[C]#include和链接的更多相关文章

  1. linux下C/C++编译时系统搜索 include 和 链接库 文件路径的指定

     C/C++程序在linux下被编译和连接时,GCC/G++会查找系统默认的include和link的路径,以及自己在编译命令中指定的路径.自己指定的路径就不说了,这里说明一下系统自动搜索的路径.   ...

  2. Ubuntu Server(Ubuntu 14.04 LTS 64位)安装libgdiplus2.10.9出错问题记录

    首先下载libgdiplus2.10.9安装包 wget http://download.mono-project.com/sources/libgdiplus/libgdiplus-2.10.9.t ...

  3. 《Entity Framework 6 Recipes》中文翻译系列 (23) -----第五章 加载实体和导航属性之预先加载与Find()方法

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-2  预先加载关联实体 问题 你想在一次数据交互中加载一个实体和与它相关联实体. ...

  4. c++ 中__declspec 的用法

    __declspec ( extended-decl-modifier-seq )扩展修饰符:1:align(#)    用__declspec(align(#))精确控制用户自定数据的对齐方式 ,# ...

  5. Qt *.pro编写一般规则

    qmake 之 CONFIG 与 QT 乱谈 看qtcn论坛中经常有人忘记 QT+=network 等语句.随便写写吧,或许对他人有帮助. 写来写去,发现越写越乱,就这样吧,反正主要的内容很简单. d ...

  6. __declspec关键字详细用法

    __declspec关键字详细用法 __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式.其它的有关存储方式的修饰符如static与extern等是C和C++语言的ANSI ...

  7. Visual C++ 设置适合自己的解决方案目录结构

    Visual C++ 使用解决方案来管理项目,项目之间还可能有依赖关系,设置适合自己的解决方案目录结构,便于代码的管理.程序的发布. 下面开始一个虚拟解决方案设计:         假设此解决方案有应 ...

  8. 实现web数据同步的四种方式

    http://www.admin10000.com/document/6067.html 实现web数据同步的四种方式 1.nfs实现web数据共享 2.rsync +inotify实现web数据同步 ...

  9. Dll学习(二)__declspec用法详解

    __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式.其它的有关存储方式的修饰符如static与extern等是C和 C++语言的ANSI规范,而__declspec是一种 ...

随机推荐

  1. C和C++从零开始系列(一)

    今天开始写下一系列C和C++从入门开始的文章. 简单说几句C和C++的关系.C语言早于C++. C语言 贝尔实验室的Ken Thompson发明了 UNIX,当时有个B语言的.后来D.M.Ritchi ...

  2. WebAPI接口的自动化测试1

    自动化测试要满足四个条件: 1 - 自动化用例能够完成所有测试步骤   -------- postman不支持  没有完整的用例管理系统 2 - 每个用例的输入数据,必须要自动填入  -------- ...

  3. 【Webpack】319- Webpack4 入门手册(共 18 章)(上)

    介绍 1. 背景 最近和部门老大,一起在研究团队[EFT - 前端新手村]的建设,目的在于:帮助新人快速了解和融入公司团队,帮助零基础新人学习和入门前端开发并且达到公司业务开发水平. 本文也是属于[E ...

  4. Java代码~~汽车租赁系统

    租车信息: 输出结果: 代码: 1.先定义抽象类(汽车类:Moto) package cn.aura.demo01; public abstract class Moto { //公共属性 priva ...

  5. Linux Bash文本操作之grep篇

    Linux grep命令用于查找文件里符合条件的字符串.是文本检索中常用的工具之一. grep  指令在文件中查找能够匹配指定模式字符串的行.如果没有指定文件名,或者文件名为  -  ,则从标准输入设 ...

  6. 重新精读《Java 编程思想》系列之类的访问权限

    Java 中,我们用访问权限修饰词确定库中的哪些类对于使用者是可以使用的. 访问权限修饰词有 public,protected,private 和什么都不写. 那么对于类来说,我们只可以用 publi ...

  7. .net(C#数据库访问) Mysql,Sql server,Sqlite,Access四种数据库的连接方式

    便签记录Mysql,Sql server,Sqlite,Access四种数据库的简单连接方式 //using MySql.Data.MySqlClient; #region 执行简单SQL语句,使用M ...

  8. CSS 选择器、字体/文本、背景

    CSS的基本使用 直接写在标签内 <p style="color: red; font-size: 40px;">段落</p> 写在 style 标签内 & ...

  9. LAMPSecurity: CTF6 Vulnhub Walkthrough

    镜像下载地址: https://www.vulnhub.com/entry/lampsecurity-ctf6,85/ 主机扫描: ╰─ nmap -p- -sV -oA scan 10.10.202 ...

  10. Java时区问题

    Java时区相关 时间格式 UTC是以原子时计时,更加精准,适应现代社会的精确计时.不过一般使用不需要精确到秒时,视为等同.GMT是前世界标准时,UTC是现世界标准时.每年格林尼治天文台会发调时信息, ...