繁体   English   中英

C->标头和变量

[英]C --> headers & variables

C中的头文件可以包含变量吗?

我是编程的初学者; 从C开始,我知道精度的重要性,尤其是在学习过程的第一步中

包括文件是由预处理器完成的,甚至在尝试编译代码之前,它只是进行文本替换-将所包含文件的内容放在要传递给编译器的当前单元中。 然后,编译器将看到连接的输出,根本看不到任何#include指令。

话虽如此,从技术上讲,您可以包括任何有效的C代码。

但是,好的做法是,标头中应仅包含类型定义,# #define ,函数声明 (而非定义 )和数据声明 (非定义 )。 函数声明也称为原型,仅指定函数签名(其返回类型,名称和参数)。 数据声明与数据定义非常相似,但是具有extern存储类说明符,无法初始化:

extern int a; // declares "a" but does not define it
extern int a = 0; // defines "a" (initialisation requested), the extern is redundant
int a; // a tentative definition (no initialisation but "a" is zeroed)

为什么在头文件中定义函数和数据不满意? 因为在链接时,包含相同头文件的不同单元将定义相同的符号,并且链接器将看到某些符号的重复定义。

还应考虑到,标头是项目其余部分(世界)的一种“公共”接口,并非源文件中定义的每个函数都需要在那里声明。 在源文件中拥有内部类型以及static函数和数据,而这些信息永远不会暴露给外界,这是完全可以的。

基本上在头文件中,我们可以声明要指向的变量,仅在其中允许声明,而不定义
让我清楚。

int a=10;  // definition

extern int a; //declaration - it can be used in another file if u include this header file.


您还可以定义宏并在头文件中声明函数。

是的,头文件可能包含变量声明,但是您通常不希望这样做,因为随着时间的推移,它会带来维护上的麻烦,尤其是当您的代码变得越来越大和越来越复杂时。 理想情况下,函数应通过参数和返回值共享信息,而不是通过使用此类“全局”数据项。

有时候你无法避免。 我没有做任何嵌入式编程,但是我的理解是,由于空间和性能的限制,使用全局变量在该领域相当普遍。

理想情况下,标头应限制为以下内容:

  • 宏定义
  • 类型定义
  • 函数声明

但是,假设您确实创建了带有变量声明的头文件,如下所示:

/**
 * foo.h
 */

int foo;

并且您有几个都包含该标头1的源文件:

/**
 * bar.c
 */
#include "foo.h"

void bar( void )
{
  printf( "foo = %d\n", foo );
}

/**
 * blurga.c
 */
#include "foo.h"

void blurga( void )
{
  foo = 10;
}

/**
 * main.c
 */
#include "foo.h"

int main( void )
{
  foo = 5;
  blurga();
  bar();
  return 0;
}

每个文件将在文件范围内(任何函数之外)包含foo的声明。 现在,您分别编译每个文件

gcc -c bar.c
gcc -c blurga.c
gcc -c main.c

给你三个目标文件- bar.oblurga.omain.o 这些目标文件中的每一个将具有其自己的foo变量的唯一副本。 但是,当我们使用以下命令将它们构建为单个可执行文件时

gcc -o foo main.o bar.o blurga.o

链接器足够聪明,可以意识到foo那些单独声明是引用同一对象的(标识符foo在这些翻译单元之间具有外部链接 )。 因此foomain初始化为5相同fooblurga套到10 ,这是相同的foobar打印出来。

但是,如果将foo的声明更改为

static int foo;

foo.h并重建文件,则这些单独的声明将不会引用同一对象; 它们将保持三个独立的且不同的对象,使得foomain初始化是一样的fooblurga套到10 ,这是不一样的foobar打印出( foo具有每个转换单元内的内部连接)。

如果必须在多个翻译单元之间使用全局变量,我的首选样式是将头文件中的变量声明为extern 2

/**
 * foo.h
 */
extern int foo;

然后在相应的.c文件中定义它

/**
 * foo.c
 */
int foo;

因此,只有一个目标文件会创建foo的实例,并且很明显 ,您打算让其他翻译单元使用它。 头文件中的声明对于共享变量不是必需的( foo标识符具有外部链接,这是通过在foo.c在任何函数之外且没有static关键字声明的简单优势),但没有它,没有其他人可以请确定您是想让它可见还是只是马虎了。

编辑

需要注意的是头没有被包含在文件的顶部; 您可能会变态并将#include指令放在函数体内

void bar( void )
{
#include "foo.h"
   // do stuff with foo
}

这样的int foo; 将在函数中处于本地状态,尽管这可能会让您受到其他程序员的殴打。 我必须在有人这样做的地方维护代码,但是25年后,它仍然让我感到恶梦。


1. 不要写这样的代码; 只是为了说明链接的概念。
2. extern关键字告诉编译器标识符所引用的对象是在其他位置定义的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM