C语言为什么一般不在.h中定义函数或者变量?(精华)

78 篇文章 1 订阅
12 篇文章 0 订阅

1、头文件的作用

大部分C编程爱好者都知道,在我们的.h文件里面经常看到的是函数的声明、变量的声明、以及各种各样的宏等等,而且在我前面的文章中我也提到过C语言的模块化设计中常常说到对应的.h和.c文件认为是一个对象,那么.h文件主要是对外的一些接口,一些私有的数据等等实现都会封装在我们的.c中,如果更加形象一点的说明我们的.h,就相当于文章下面的推荐文章链接组成的框,点进去就到了对应的具体文章,具体的文章也就是我们的.c文件了。

这里再回到我们的程序中来,如下代码所示:

  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. int sAdd(int a,int b);

  4. int sSub(int a,int b);

  5. //...

  6. int main(int argc, char *argv[]) {

  7. printf("Add: %d\n",sAdd(1 , 1));

  8. printf("Sub: %d\n",sSub(1 , 1));

  9. printf("公众号:最后一个bug\n");

  10. return 0;

  11. }

  12. /***************************************

  13. * Fuction:sAdd

  14. * Author : (公众号:最后一个bug)

  15. ***************************************/

  16. int sAdd(int a,int b)

  17. {

  18. return (a + b);

  19. }

  20. /***************************************

  21. * Fuction:sSub

  22. * Author : (公众号:最后一个bug)

  23. ***************************************/

  24. int sSub(int a,int b)

  25. {

  26. return (a - b);

  27. }

  28. //...

解析一下: 上面是大部分小伙伴最开始学习编程的时候做法,那么我们把main函数前面的声明放到一个对应的.h文件,加法与减法的具体实现放到对应的.c文件,然后再main函数前面用#include "xxx.h",便可以了。简单点说.h完全可以直接在#include处进行展开以便于我们理解分析。

2、头文件中定义函数或者变量

代码阅读量比较多的小伙伴应该见过直接在头文件里面定义函数或者变量的做法,那么这里我们直接对上面进行改造,得到如下代码:

  1. //Filename: main.c

  2. #include <stdio.h>

  3. #include <stdlib.h>

  4. #include "Add.h"

  5. int main(int argc, char *argv[]) {

  6. printf("Add: %d\n",sAdd(global_Var1 , global_Var2));

  7. printf("Sub: %d\n",sSub(global_Var1 , global_Var2));

  8. printf("公众号:最后一个bug\n");

  9. return 0;

  10. }

 
 
  1. //Filename : Add.h

  2. /***************************************

  3. * Fuction:sAdd

  4. * Author : (公众号:最后一个bug)

  5. ***************************************/

  6. int global_Var1 = 2;

  7. int global_Var2 = 2;

  8. /***************************************

  9. * Fuction:sAdd

  10. * Author : (公众号:最后一个bug)

  11. ***************************************/

  12. int sAdd(int a,int b)

  13. {

  14. return (a + b);

  15. }

  16. /***************************************

  17. * Fuction:sSub

  18. * Author : (公众号:最后一个bug)

  19. ***************************************/

  20. int sSub(int a,int b)

  21. {

  22. return (a - b);

  23. }

 

解析一下:上面的程序也能够成功编译并运行,并且能够获得正确的结果,这也进一步证明直接展开#include "xxx.h"是可以解释得通的。

3、为什么不选择在头文件定义变量或者函数

1)多个源文件声明.h会重复定义 

我们如果按照上面的展开法进行解释,其实很好理解多个源文件声明#include "xxx.h"会导致多个相同的全局变量和函数,这样必然导致重复定义故障,如果小伙伴们不信我直接敲代码看结果:

 

 
 
  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. #include "APP1.h"

  4. #include "APP2.h"

  5. /*********************************************

  6. * Fuction:main

  7. * Author : (公众号:最后一个bug)

  8. ********************************************/

  9. int main(int argc, char *argv[]) {

  10. printf("%d\n",add_APP1(1,1));

  11. printf("%d\n",add_APP2(1,1));

  12. return 0;

  13. }

 
 
  1. //Filename:Add.h

  2. /*********************************************

  3. * Fuction:add

  4. * Author : (公众号:最后一个bug)

  5. ********************************************/

  6. int add(int a,int b)

  7. {

  8. return (a + b);

  9. }

 
 
  1. //Filename:App1.h

  2. int add_APP1(int a,int b);

 
 
  1. //Filename:App1.c

  2. #include "Add.h"

  3. /*********************************************

  4. * Fuction:add_APP1

  5. * Author : (公众号:最后一个bug)

  6. ********************************************/

  7. int add_APP1(int a,int b)

  8. {

  9. return add(a,b);

  10. }

 

 

解析:APP2对应的.c和.h我就不再贴上去了,毕竟代码比较简单。最后一张图为编译结果,第二行显示重复定义add这个函数。同样作者也进行了对变量一样的做法,同样也是显示的是重复定义相关变量,所以也验证了我们的前面的理论。

2)添加条件编译#ifndef 

我们大部分小伙伴可能会想我们直接在头文件的函数和变量定义加上条件编译#ifndef来避免重复包含不就可以了吗?好了,作者也进行了这个实验大家简单看看代码和结果,后面我来解释下:

  1. //Filename:Add.h

  2. /*********************************************

  3. * Fuction:add

  4. * Author : (公众号:最后一个bug)

  5. ********************************************/

  6. #ifndef __ADD_H__

  7. #define __ADD_H__

  8. int add(int a,int b)

  9. {

  10. return (a + b);

  11. }

  12. #endif

 

解析一下:加了该预编译以后其结果与上一节的结果一致,还是提示重复定义该函数。那是为什么呢?我在前面的《嵌入式编程有道-C语言(1)》中有描述C程序到机器码的一个生成过程,App1.c和App2.c分别编译,然后分别展开#include,在最后的链接过程中发现了同名的函数和变量,所以还是会编译不通过。

3)static能够帮我们搞定这种窘境 

我们都知道static表示静态的的意思,也可以说是对变量和函数进行文本上的限制,多个文件中是可以有同名的static函数和变量的,不过他们却代表着不同的函数和变量,这一点要尤为注意,如果该头文件在不同文件中大量使用其中的变量和函数也会导致程序的增加和内存的变大,下面作者就为这几点用程序来证明下:

 
 
  1. //Filename:Add.h

  2. #ifndef __ADD_H__

  3. #define __ADD_H__

  4. static int add(int a,int b)

  5. {

  6. return (a + b);

  7. }

  8. #endif

 
 
  1. //filename:App1.c

  2. #include <stdio.h>

  3. #include "Add.h"

  4. /*********************************************

  5. * Fuction:add_APP1

  6. * Author : (公众号:最后一个bug)

  7. ********************************************/

  8. int add_APP1(int a,int b)

  9. {

  10. printf("add_APP1_addFuc:0x%x\n",(int*)add);

  11. return add(a,b);

  12. }

 

 解析一下:上面仅仅贴了重要的两段,代码比较简单,我们发现两个里面都是调用的add,但是他们的地址是不相同的,说明他们并不是一个函数。所以大家也可以把Add.h文件用我们模块化设计的思想分为一个.c和一个.h的形式,最后打印的地址是一样的,代码我就不贴了给大家看一下结果即可,地址是一样的说明他们是同一个函数,同样大伙也可以用static修饰变量,也是得到类似的结果。

 

4、小节

最后小节一下,其实为什么大家一般不在.h文件里面定义变量或者函数其实原因还有很多,最主要的是不符合相关设计要求,比如进行代码上的改动话,编译会造成连锁反应导致编译时间再次编译时间较长等问题,同时代码上的分析比较麻烦,所以大家对于这类问题其实也是可以平时闲暇时候好好研究一下,同时你会在其中收获很多意外的知识点,要做到"知其然而知其所以然",其实在头文件中定义函数或者变量并不是没有这样的设计需求,大家可以考虑一下static在头文件中定义的这种使用有缺点,是否会有什么优点呢?哈哈,这里我就不揭秘了,请听下回分解!


资源交流获取关注公众号:奇牛编程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 外部变量定义文件外部(非函数内部)的变量。它们可以被多个文件的函数访问和修改。 在 C 语言定义外部变量的方式是在文件的顶部(非函数内部)添加变量的声明,并在其他文件通过 extern 关键字来引用它。例如,在文件1定义外部变量x: ``` int x; ``` 在文件2引用这个变量x: ``` extern int x; ``` ### 回答2: C语言,外部变量是指在一个函数之外定义变量,它的作用域从定义处开始,到文件的结尾为止。外部变量可以在整个C程序被访问和使用,具有全局的范围和生命周期。 外部变量的意义在于: 1. 数据共享:外部变量可以在不同的函数之间共享数据,避免了函数之间传递参数的复杂性和开销。 2. 面向对象的模块化编程:外部变量可以作为不同模块之间交流和协作的桥梁,方便模块之间的数据传递和共享。 3. 简化代码结构:外部变量可以减少函数内部的参数传递,简化函数的接口和实现,提高代码的可读性。 在C程序定义外部变量时,需要将变量的声明放置在函数之外、程序的顶部。例如: ```c #include <stdio.h> int globalVariable; // 定义了一个外部变量globalVariable int main() { globalVariable = 10; // 可以在函数直接使用外部变量 printf("%d", globalVariable); return 0; } ``` 在其他函数使用外部变量时,不需要再次进行声明,只需要直接使用即可。如果在其他函数需要修改外部变量的值,同样不需要进行声明,直接赋值即可。 需要注意的是,为了安全起见,尽量避免过多使用外部变量,因为它们可能会导致代码的可读性和维护性降低。合理使用外部变量能够提高代码的灵活性和可扩展性,但也需要谨慎使用,遵循良好的编程习惯。 ### 回答3: C语言的外部变量具有全局作用域,可以被程序的多个函数共享和访问,有以下几个意义: 1. 数据共享:外部变量可以在程序的多个函数被访问和修改,实现数据在不同函数之间的共享。 2. 提高代码复用性:通过使用外部变量,可以将需要在多个函数使用的数据定义为外部变量,避免了重复定义和传递数据的麻烦。 3. 灵活性:外部变量可以在任意的函数定义和修改,可以方便地在函数之外对其进行操作。 在C程序定义外部变量有以下几种方法: 1. 在函数之外定义:在所有函数之外定义一个变量,它就成为了外部变量,可以被所有函数访问。例如: ``` int count; // 外部变量定义 ``` 2. 使用关键字extern:在函数之外声明一个外部变量,然后在其他函数使用关键字extern来引用该变量。例如: ``` extern int count; // 外部变量声明 void func() { count = 10; // 使用外部变量 } ``` 3. 使用头文件:将外部变量定义放在一个头文件,然后在需要使用该变量的函数包含这个头文件即可。通过这种方式,可以在多个源文件共享外部变量。 需要注意的是,为了避免重复定义,外部变量定义只能在一个源文件进行,而其他源文件只能使用extern关键字来声明该变量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值