为什么某些功能的extern声明,头文件不包含在Git的源$ C ​​$ C源? [英] Why are some functions declared extern and header file not included in source in Git source code?

查看:249
本文介绍了为什么某些功能的extern声明,头文件不包含在Git的源$ C ​​$ C源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想看到一个真实的世界应用程序的源$ C ​​$ C,了解良好的编程习惯等,所以我选择了Git和下载的源1.8.4版本。

I wanted to see the source code of a real world application to understand good programming practices etc. So I chose Git and downloaded the source for version 1.8.4.

通过各种文件随机浏览的东西后,引起了我的注意这两个文件: STRBUF .H strbuf.c

After randomly browsing through various files something caught my attention in these two files: strbuf.h strbuf.c

这两个文件显然定义与本文档

These two files apparently define an API with this documentation.

我有两个问题:


  1. 为什么在行16,17,18,19和放大器的函数声明;在strbuf.h6号线的全局变量声明为extern?

  1. Why the function declarations at line 16,17,18,19 & global variable at line 6 in 'strbuf.h' declared extern ?

为什么strbuf.h不是STRBUF .C执行#included?

Why "strbuf.h" is not #included in strbuf .c ?

我作为一个新手程序员始终了解到你写函数定义的.c文件,而函数声明,宏,内联等写入在.h文件中,然后在每一个想要.c文件包含(#include)要使用这些功能等。

I as a novice programmer have always learned that you write function definitions in a .c file whereas the function declarations,macros,inlines etc. are written in a .h file which is then #included in every .c file which wants to use these functions etc.

任何人都可以请解释一下吗?

Can anyone please explain this?

推荐答案

strbuf.c 包括 cache.h cache.h 包括 strbuf.h ,所以你的premise问题2(即 strbuf.c 不包括 strbuf.h )是错误的:它不包含它,只是没有直接

strbuf.c includes cache.h and cache.h includes strbuf.h, so your premise for question 2 (that strbuf.c does not include strbuf.h) is wrong: it does include it, just not directly.

从未所需的的extern 关键字为函数声明,但它确实有效果:它声明的标识符命名的功能(即函数名)有相同的链接任何previously可见的声明,或者如果没有这样的声明是可见的,该标识符有外部链接。这相当混乱的措辞确实意味着,给定:

The extern keyword is never required for function declarations, but it does have an effect: it declares that the identifier naming the function (i.e., the function's name) has the same linkage as any previously visible declaration, or if no such declaration is visible, that the identifier has external linkage. This rather confusing phrasing really means that, given:

static int foo(void); extern int foo(void);

的第二个声明还宣称它静态,给它内部链接。如果你写的:

the second declaration of foo also declares it static, giving it internal linkage. If you write:

static int foo(void); int foo(void); /* wrong in 1990s era C */

您第一次宣布它具有内在的联系,和C,那么第二个具有外部链接,并在pre-1999年的版本中, 1 产生不确定的行为。从某种意义上说,届时,的extern 关键字增加了一些安全性(在混乱的价格),因为它可能意味着静态必要时。但你总是可以写静态再次和的extern 不是万能的:

you have declared it first as having internal linkage, and then second as having external linkage, and in pre-1999 versions of C,1 that produces undefined behavior. In one sense, then, the extern keyword adds some safety (at the price of confusion) as it can mean static when necessary. But you could always write static again, and extern is not a panacea:

extern int foo(void); static int foo(void); /* ERROR */

这第三种形式仍然是错误的。第一个的extern 声明没有previous可见的声明,因此的外部链接,然后在第二个静态声明给出了内部联动,产生不确定的行为。

This third form is still erroneous. The first extern declaration has no previous visible declaration, so foo has external linkage, and then the second static declaration gives foo internal linkage, producing undefined behavior.

在短,的extern 不需要在函数声明。有些人只是preFER它风格的原因。

In short, extern is not required on function declarations. Some people just prefer it for style reasons.

(注:我离开了 extern内联在C99,这是一种奇怪的,和实现各不相同见的 http://www.greenend.org.uk/rjk/2003/03/inline.html 了解详细信息。)

(Note: I'm leaving out extern inline in C99, which is kind of weird, and implementations vary. See http://www.greenend.org.uk/rjk/2003/03/inline.html for more details.)

的extern 关键字是否有多种不同的效果。首先,作为与函数声明,它会影响识别符的链接。第二,对于任意函数(一个全局变量中的两种常用的感官一个)以外的标识符,它导致声明是声明,而不是一个定义,所提供的变量未还初始化

The extern keyword on a variable declaration has multiple different effects. First, as with function declarations, it affects the linkage of the identifier. Second, for an identifier outside any function (a "global variable" in one of the two usual senses), it causes the declaration to be a declaration, rather than a definition, provided the variable is not also initialized.

有关在函数内部变量(即用块范围),如 somevar

For variables inside a function (i.e., with "block scope"), such as somevar in:

void f(void) {
    extern int somevar;
    ...
}

的extern 关键字使标识有一定的联动(内部或外部),而不是没有联系(如自动持续时间的局部变量)。在这个过程中,它也使变量本身具有静态持续时间,而不是自动的。 (自动持续时间的变量,从来没有联动,始终有块范围,而不是文件范围。)

the extern keyword causes the identifier to have some linkage (internal or external) instead of "no linkage" (as for automatic-duration local variables). In the process, it also causes the variable itself to have static duration, rather than automatic. (Automatic-duration variables never have linkage, and always have block scope, rather than file scope.)

与函数声明,联动的extern 分配,如果有一个previous可见的内部联动声明,否则外部是内部的。因此, X F()在这里有内在的联系,尽管的extern 关键字:

As with function declarations, the linkage extern assigns is internal if there is a previous visible internal-linkage declaration, and external otherwise. So the x inside f() here has internal linkage, despite the extern keyword:

static int x;
void f(void) {
    extern int x; /* note: don't do this */
    ...
}

写这类code的唯一原因是混淆其他程序员,所以不要做。 : - )

The only reason to write this kind of code is to confuse other programmers, so don't do it. :-)

在一般情况下,有理由注释与的extern 关键字是$ P全球(即文件范围,静态的持续时间,外部联动)变量$成为一个定义pvent这种特殊声明。使用所谓的高清/ REF模式的C编译器在链接时消化不良当相同的名称被定义一次以上。因此,如果 file1.c中表示, INT globalvar; file2.c中还说 INT globalvar; ,都是定义和code可能无法编译(虽然大部分类Unix系统使用所谓的通用模型默认情况下,这使得这项工作反正)。如果你是在一个头,宣布这样的变量文件是可能被纳入从许多不同的 .C 文件使用的extern 来作出这样的声明只是一个声明。

In general, the reason to annotate "global" (i.e., file-scope, static-duration, external-linkage) variables with the extern keyword is to prevent that particular declaration from becoming a definition. C compilers that use the so-called "def/ref" model get indigestion at link time when the same name is defined more than once. Thus, if file1.c says int globalvar; and file2.c also says int globalvar;, both are definitions and the code may not compile (although most Unix-like systems use the so-called "common model" by default, which makes this work anyway). If you are declaring such a variable in a header file—which is likely to be included from many different .c files—use extern to make that declaration "just a declaration".

一,并且只有一个,那些 .C 文件可话又说回来声明变量,留下关闭的extern 关键字和/或包括初始化。或者,有些人preFER在头文件中使用类似于这种风格:

One, and only one, of those .c files can then declare the variable again, leaving off the extern keyword and/or including an initializer. Or, some people prefer a style in which the header file uses something like this:

/* foo.h */
#ifndef EXTERN
# define EXTERN extern
#endif
EXTERN int globalvar;

在此情况下,一个(也是唯一一个)那些 .C 文件可以包含序列:

In this case, one (and only one) of those .c files can contain the sequence:

#define EXTERN
#include "foo.h"

下面,因为 EXTERN 的定义中,的#ifndef 关闭后续#定义与行 EXTERN INT globalvar; 扩展到刚 INT globalvar; 使这一成为一个定义,而不是一个声明。就个人而言,我不喜欢这种编码风格,虽然它确实满足了不要重复自己的原则。主要是我找到大写 EXTERN 误导,而这种模式是无益的在初始化。这些谁赞成它通常清盘添加第二个宏隐藏初始化:

Here, since EXTERN is defined, the #ifndef turns off the subsequent #define and the line EXTERN int globalvar; expands to just int globalvar; so that this becomes a definition rather than a declaration. Personally, I dislike this coding style, although it does satisfy the "don't repeat yourself" principle. Mostly I find the uppercase EXTERN misleading, and this pattern is unhelpful with initialization. Those who favor it usually wind up adding a second macro to hide the initializers:

#ifndef EXTERN
# define EXTERN extern
# define INIT_VAL(x) /*nothing*/
#else
# define INIT_VAL(x) = x
#endif

EXTERN int globalvar INIT_VAL(42);

但即使这样分崩离析的时候(例如,结构应该被初始化为 {42初始化该项目需要一个复合初始化, 23日,17日,滚开!} )。

(注意:我特意在整个暂定定义这里的东西没有掩盖一个初始的定义只是暂定规定,直到翻译单元的结束这使得某些类型的向前引用,这一点是否则太难前preSS,这是不正常很重要。)

(Note: I've deliberately glossed over the whole "tentative definition" thing here. A definition without an initializer is only "tentatively defined" until the end of the translation unit. This allows certain kinds of forward-references that are otherwise too difficult to express. It's not normally very important.)

这是一个好主意,一个简单的原因:编译器将在对阵头比较声明的F()定义的F()在code。如果这两个不匹配(在初始编码任何理由通常是一个错误,或未能及时更新这两个维护过程中的一个,但偶尔只是由于猫踩踏键盘综合症或类似),编译器可以捕捉到错误在编译时。

This is always a good idea, for one simple reason: the compiler will compare the declaration of f() in the header against the definition of f() in the code. If the two do not match (for any reason—typically a mistake in initial coding, or a failure to update one of the two during maintenance, but occasionally simply due to Cat Walked On Keyboard Syndrome or similar), the compiler can catch the mistake at compile time.

1 1999年C标准说,在函数声明中省略了的extern 关键字意味着同样的事情,使用 EXTERN 关键字那里。这是更简单来形容,并意味着你定义的(和明智的)行为,而不是不确定的(因此也许好也许坏行为)。

1The 1999 C standard says that omitting the extern keyword in a function declaration means the same thing as using the extern keyword there. This is much simpler to describe, and means you get defined (and sensible) behavior instead of undefined (and therefore maybe-good maybe-bad behavior).

这篇关于为什么某些功能的extern声明,头文件不包含在Git的源$ C ​​$ C源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆