首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么C语言会有头文件

前段时间一个刚转到C语言的同事问我,为什么C会多一个头文件,而不是像Java和Python那样所有的代码都在源文件中。...其实我在准备这些例子的时候也是这样,很多时候没有注意相关代码的顺序导致报错,而针对重复定义的报错很难排查。...这样就解释了为什么在声明时指定变量类型,如果编译器不知道类型就不知道该用什么指令来替换C代码。同时会将对应的变量名作为符号保留。...然后在符号表(这个符号表时每个代码文件都有一个)中填入该文件中定义的相关内容的符号以及它所在的首地址。最终如果未发生错误就生成了一个对应的.obj文件,这就是编译的基本过程。...当它发现找到多个地址的时候就会报重复定义的错误。

2.2K50

C语言预处理详解

预定义符号 C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。...ANSI C,其值为1,否则未定义 举个例⼦ 这里就使用了date和time这两个预定义符号程序就打印出了此时的时间和日期, 其他的我就不一一列, 2....define DOUBLE(x) (x) + (x) 定义中我们使⽤了括号,想避免之前的问题,但是这个宏可能会出现新的错误。...#undef NAME //如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除。 10. 命令⾏定义 许多C的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。...件中将test.h包含5次,那么test.h⽂件的内容将会被拷⻉5份在test.c中。

5600
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    C++编译与链接(2)-浅谈内部链接与外部链接

    为什么有时会出现无法解析的外部符号? 为什么有的内联函数的定义需要写在头文件中? 为什么对于模板,声明和定义都要写在一起?...最后让我们回到文章开头处的那几个问题吧 为什么有时会出现aaa已在bbb中重定义的错误?...答:你可能在不同的cpp中重复定义了一个具有外部链接的函数或变量,链接器在链接时找到了多个一样的函数或变量定义 为什么有时会出现无法解析的外部符号?...答:你可能只提供了函数或变量的声明,没有提供其定义,或者声明和定义的函数原型不一致,链接器没有找到其定义在哪里,所以在链接环节出现了无法解析的外部符号的错误 为什么有的内联函数的定义需要写在头文件中呢?...,便会出现无法解析的外部符号的错误 为什么对于模板,声明和定义都要写在一起呢?

    4K110

    关于模板函数声明与定义的问题

    大家好,又见面了,我是你们的朋友全栈君。 c++ primer上说:c++模板函数的声明与定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?...此时编译main.cpp单元不会报错,但链接就会出现add函数未定义的错误。...如果类模板的成员函数的定义与类的定义不在同一个编译单元中(分离式编译),此时调用类的成员函数便会出现未定义的错误。而当我们像代码中那样在某个地方显式的调用它的时就不会出现此类问题了。...c++primer上面只说了类模板的成员函数可以不在头文件中定义,却始终感觉说得不清不楚,因为实际上像普通类那样类的定义与实现放在不同的文件中的话,是会链接出错的。...总之,若你不想出现任何未定的错误,将类模板或函数模板的定义与声明放在同一个文件中就行了。

    2.4K30

    预处理详解

    1.预定义符号 C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。...(a):(b)) 那为什么不⽤函数来完成这个任务? 原因有⼆: ⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐函数在程序的规模和速度⽅⾯更胜⼀筹。...宏可能会带来运算符优先级的问题,导致程容易出现错。 宏有时候可以做函数做不到的事情。⽐如:宏的参数可以出现类型,但是函数做不到。...#undef NAME //如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除。 10. 命令⾏定义 许多C 的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。...test.h包含5次,那么test.h⽂件的内容将会被拷⻉5份在test.c中。

    10510

    【C语言】预处理

    预定义符号 C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。...(a):(b)) 那为什么不用函数来完成这个任务? 原因有二: 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。...宏可能会带来运算符优先级的问题,导致程容易出现错。 宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到。...#undef NAME //如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除。 10. 命令行定义 许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。...test.h包含5次,那么test.h文件的内容将会被拷贝5份在test.c中。

    8810

    C语言——R预处理详解

    一、预定义符号 C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。...⼀个宏定义: #define DOUBLE(x) (x) + (x) 定义中我们使⽤了括号,想避免之前的问题,但是这个宏可能会出现新的错误。...最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 1. 宏参数和#define定义中可以出现其他#define定义的符号。...宏可能会带来运算符优先级的问题,导致程容易出现错。 宏有时候可以做函数做不到的事情。⽐如:宏的参数可以出现类型,但是函数做不到。...十、命令行定义 许多C的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。 例如:当我们根据同⼀个源⽂件要编译出⼀个程序的不同版本的时候,这个特性有点⽤处。

    13910

    C语言:预处理详解

    一、预定义符号 C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。...如果是,就重复上 述处理过程 注意: 1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。...宏可能会带来运算符优先级的问题,导致程容易出现错。 6.3 宏有时可以做到函数做不到的事情 宏的参数可以出现类型,但是函数做不到!!...#undef NAME //如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除。 十一、命令行定义 许多C 的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。...而参数a是在执行程序的过程中才出现的!所以对于条件编译来说,他并不认识a!

    35110

    C语言预处理详解

    预定义符号 C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。...(a):(b)) 那为什么不⽤函数来完成这个任务? 原因有⼆个: 1. ⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐ 函数在程序的规模和速度⽅⾯更胜⼀筹。...宏可能会带来运算符优先级的问题,导致程容易出现错 宏有时候可以做函数做不到的事情。⽐如:宏的参数可以出现类型,但是函数做不到。...#undef NAME //如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除 10. 命令⾏定义 许多C 的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。...件中将test.h包含5次,那么test.h⽂件的内容将会被拷⻉5份在test.c中。

    8410

    SQL注入的几种类型和原理

    有读者可能会迷惑,我还是解释一下,读库、读表、读字段、读数据。我这里使用了几个函数,连接字符的group_concat,指定分割符连接的 concat_ws。...对于报错,回显在错误中,后面的的时间注入,回显在时间的判断中,DNSlog盲注中,回显在DNSlog中。 报错注入如何发生的? 构造payload让信息通过错误提示回显出来 什么场景下有用?...笔者在看到这个语句的时候其实是有疑惑的。 为什么构造的语句为第二个参数?我理解函数执行过程中,第二个参数像正则匹配一样从第一个参数中匹配出结果。...操作第二个参数能直接的触发错误 为什么使用concat函数?...为什么使用concat函数中第一个参数构造了一个波浪号?其实这个原因和上面一样,构造非法的参数,这样才能在错误中看到后面完整的数据。 ?

    5.4K52

    阿榜的生信笔记2

    大家仔细阅读文章哦,等会大家就知道答案了 三、对一个向量进行操作: ①、向量赋值输出: 小技巧:规范的赋值符号 Alt+减号相当于=,有两种“赋值+输出一起实现”方式 #####2.2对单个向量进行的操作...+函数名查看帮助文档,这相当于我们会查R语言字典了 四、对两个向量进行操作 ①、比较运算: #####2.3.对两个向量进行的操作##### x = c(1,3,5,1) y = c(3,2,5,6)...进行参照,输出y的剩余部分 x %in% y #x的每个元素在y中存在吗?...y %in% x #y的每个元素在x中存在吗? 注意:x %in% y #x的每个元素在y中存在吗?即以x为主体,检验x的每个元素在y中存在吗? y %in% x #y的每个元素在x中存在吗?...好的,以上是我这次在学习生物信息学过程中所整理的笔记。如果在笔记中有错误或者不足之处,欢迎大家指正,我们一起加油鸭? 引用自生信技能树——小洁老师

    40300

    C语言从入门到实战——预处理详解

    因此,在使用预处理器时需要谨慎,避免产生预期之外的结果。 一、预定义符号 C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。...这个宏在调试和错误排查中非常有用,可以帮助开发人员快速定位代码中的问题。...最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 宏参数和#define定义中可以出现其他#define定义的符号。...比如在两个数中找出较大的一个时,写成下面的宏,更有优势一些。 #define MAX(a, b) ((a)>(b)?(a):(b)) 那为什么不用函数来完成这个任务?...#line 指令通常用于调试和错误报告中,可以帮助开发人员更好地跟踪代码的执行过程或报告错误时准确指示错误位置。 需要注意的是,#line 指令的有效范围通常只在它出现之后的部分。

    60711

    【C语言】预处理详解

    预定义符号 C语言设置了一些预定义符号, 可以直接使用 ,预定义符号也是在 预处理期间 处理的。...C 注:预定义符号在预处理间就被替换了 2....如果是,就重复上述处理过程。 注意: 1. 宏参数 和 #define 定义 中可以出现其他#define定义的符号。但是对于宏,不能出现递归。 2....宏可能会带来运算符优先级的问题,导致程容易出现错。 宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到。...比如: 这个MAX不是被定义了嘛,因为#undef出现所以取消了MAX定义,此刻MAX未定义 10. 命令行定义 许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。

    9210

    代码宏的一点小知识

    本文是一篇关于宏定义的短文 C/C++ 中我们可以定义宏来做一些代码的简化工作,一般我们不推荐使用宏,因为使用过程中很容易出现问题,目前有一些方法可以用来取代宏的部分功能(譬如内联函数),但是仍然有些宏功能现在还没有更可靠方便的替代方法...(a) : (b)) 上述宏定义了一个 MAX 宏,用以返回两个宏参数中较大的参数,这里需要注意一下,如果你使用带有副作用的宏参数,上面的 MAX 宏会返回意外的结果(因为宏并不是函数,宏本身只是做了代码的替换...我们也可以定义多行宏,方法就是在每一行的宏定义之后添加 \ 符号(最后一行不用添加 \ 符号): #define MULTI_LINE_MACRO do {\ ++i; \ } while(false)...) \ { \ return; \ } 上面代码中我定义了两个宏(MACRO_1 和 MACRO_2),代码上看两者似乎是一致的,但是执行编译的话, MACRO_2 却会在最后一行出现错误(MACRO...有兴趣的朋友可以仔细找找(不必马上往下看结论)~ ---- 我一开始也觉得颇为奇怪,后来仔细查看之后才发现, MACRO_2 中的这一句定义: return; \ \ 符号之后是有空格符的!

    32130

    C ++ 中不容忽视的 25 个 API 错误设计!

    误#2:在你的公共API头的全局范围中包含“using namespace” 为什么这是一个错误? 这将导致被引用命名空间中的所有符号在全局命名空间中变得可见,并首先抵消掉使用命名空间的好处。...从API设计的角度来看,隐式实例化受到以下问题的困扰: 编译器现在负责在适当的位置滞后地实例化代码,并确保只存在该代码的一个副本以防止重复符号的链接错误。这会对你的客户端的构建和链接时间造成影响。...请确保这是你的API的预期用例。 错误#11:在默认函数参数中公开内部值 为什么这是个问题 ? 默认参数通常用于在较新版本中扩展API,以便不会破坏API的向后兼容性来增强功能。...实际上,.Net中的[InternalsVisible]属性确实起到了类似的作用。 但是,友元类不应该在公共API中公开。 为什么在C ++中使用friend是个错误?...我发现当没有流程时会出现多个问题,包括: 该API不符合Beta客户的使用案例(通常情况下,人们会等到Beta客户后再查看API。) API与系统的其他部分或同一系列产品不相似。

    1.6K20

    【C语言】编译和链接(编译环境和运行环境)

    ("%d\n", ret); return 0; }    当我们实现好这两个文件后,直接运行后发现出现了错误,我们来看看具体报错:    它说函数add未定义,a是没有声明的标识符,这是为什么呢...例如,定义的static函数和变量 接下来我们可以简单的画出add.c中的符号表,在画的时候我们要注意,在add.c中并没有外部符号的引用,出现的符号add拥有正常的声明和定义,所以会直接分配一个虚拟地址...,如图:    接下来我们就来画test.c的符号表,为了进行对比,在test.c的符号表中我们也只画出只有add符号的符号表,其它符号就省略掉,如下图:    可以对比看出来,在add.c中,...add符号被看做全局符号,拥有自己的地址,但是在test.c中,add符号被看做外部符号,只有一段可能错误的地址(不一定就是0地址)    链接中关键的就是这一步,由于test.c不认识这个符号所以要报错...test.c中add符号的地址,使它正确,会进行重定位操作,重定位会计算每个定义的符号在虚拟地址空间的绝对地址,将可执行文件中的符号引用处修改为重定位后的地址信息    将符号表修正后,test.c文件的符号表中的

    12010

    程序环境和预处理

    链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人 的程序库,将其需要的函数也链接到程序中。...宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。 2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。...宏可能会带来运算符优先级的问题,导致程容易出现错。 宏有时候可以做函数做不到的事情。...带 有 副 作 用 的 参 数 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果。 函数参数只在传参的时候求值一 次,结果更容易控制。...#undef NAME //如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。 3.4 命令行定义 许多C 的编译器提供了一种能力,允许在命令行中定义符号。

    8410

    【C语言】预处理&&编译链接&&调试技巧详解

    如果是,就重复上述处理过程 注意: 宏参数和#define定义中可以出现其他#define定义的符号。...(a):(b)) 那为什么不用函数来完成这个任务?...宏可能会带来运算符优先级的问题,导致过程容易出现错误 宏有时候可以做函数做不到的事情,比如:宏的参数可以出现类型,但是函数做不到 对比 建议: 如果逻辑比较简单,可以使用宏来实现 如果计算逻辑比较负责...(object code) 每个目标文件文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库...c文件,如何在一个.c文件中调用另一个.c文件中的函数呢 这里我们了解一个概念叫做符号汇总 假设有这样的代码 进行符号汇总 注意:符号汇总只能汇总全局变量 2.3.1.3 汇编 把汇编代码翻译成了二进制的指令

    32310

    h文件和c文件的区别include本身只是一个简单的文件包含预处理命令,即为把include的后面文件放到这条命令这里,除此之外,没有其它的用处(至少我也样认为).

    好久没看C了,本来就忘得一干二净的,一脸懵逼的看着zend。 关于.c 和 .h 的区别 子程序不要定义在.h中。函数定义要放在.c中,而.h只做声明.否则多引用几次,就会发生函数重复定义的错误。...” 当然,如果一个 .h 被多个 .c 包含,而且 .h 中有对象(变量或函数)的定义,就会发生重复定义的错误了.声明可以无穷多次,定义只能一次 一般来说,一个C文件应该是一个模块,如果你的程序仅仅有一个模块...编译器就会将之放入BSS段,连接器会对BSS段的多个同名变量仅分配一个存储空间 3.如果在C文件中声明宏,结构体,函数等,那么我要在另一个C文件中引用相应的宏,结构体,就必须再做一次重复的工作,如果我改了一个...1.为什么经常见 xx.c 里面 include 对应的 xx.h? 2.如果 a.c 中不写,那么编译器是不是会自动把 .h 文件里面的东西跟同名的 .c 文件绑定在一起?...但是如果.c中的函数也需要调用同个.c中的其它函数,那么这个.c往往会include同名的.h,这样就不需要为声明和调用顺序而发愁了(C语言要求使用之前必须声明,而include同名.h一般会放在.c的开头

    1.6K20

    C++ 温习笔记(1) - main函数,类对象,作用域,防止头文件二次编译

    (4) 静态变量 关键字static有一些独特的意义。通常,函数中定义局部变量在函数中作用域结束时消失。当再次调用这个函数时,会重新创建变量的存储空间,其值会被重新初始化。...我们可能奇怪为什么不使用全局变量。static局部变量的优点是在函数范围之外它是不可用的,所以它不可能被轻易改变。这会使错误局部化。...而macro.h有: #include 现在可以发现我们在main和macro中重复引用了key.h这样一个头文件 这就叫重复引用 防止重复引用的方法就是在每个头文件中加上ifndef/define.../endif条件编译语句 头文件重复引用是指一个头文件在同一个CPP文件中被INCLUDE了多次,这种错误常常是由于INCLUDE 嵌套造成的。...那么x.h在此也同样被包含了两次,只不过它的形式不是那么明显而已。 多重包含在绝大多数情况下出现在大型程序中,它往往需要使用很多头文件,因此要发现重复包含并不容易。

    1.1K10
    领券