[英]Does the order of C objects matter?
C 对象出现在文件上的顺序是否重要?
例如,在函数中,如果我创建了两个函数并且上面的一个引用了另一个函数,它会起作用吗? (是的,我试过了。)对于 static 函数、INLINE 函数等是否同样有效? 结构的效果是否相同? 如果我引用在.c 文件中进一步定义的结构会发生什么?
这是任何扩展编译器特定的吗? 在这种情况下编译器如何工作? 它是否首先扫描整个文件以查找所有声明/定义,然后尝试取消引用函数/符号?
首先,如果通过“如果我创建两个函数并且上面的一个引用另一个函数会起作用吗?” 你的意思是这样的:
int foo()
{
return bar();
}
int bar()
{
return 0;
}
然后编译器可能会对bar()
是什么进行有根据的猜测,但如果bar()
尚未声明,它至少会发出警告。 对于无法调用的符号(如变量或类型),如果在声明它们之前使用它们,那将是一个彻头彻尾的错误。
在 C 中,无论何时使用标识符(无论标识符的种类:它可能是 function、变量、类型等),都应事先声明。 您可以添加到任何标识符的各种修饰符(如您所说, static
, inline
和所有其他修饰符)对此没有影响。
不要混淆声明和定义。 声明只是告诉编译器名称存在; 定义实际上告诉编译器它是什么。
例如,这是一个定义:
int bar() { return 4; }
注意它是如何有一个主体的,里面有(简单的)代码。
这是匹配的声明:
int bar();
编译器一看到它的声明或定义,就会很乐意接受 function 的使用。 出于组织原因和更好的灵活性,通常最好在 C 文件的顶部(或在包含的 header 文件中)编写所有函数的声明,然后是定义。
所以,我的第一个例子应该是这样的:
int foo();
int bar();
int foo()
{
return bar();
}
int bar()
{
return 0;
}
使用 C 代码上方的声明,我可以以任何我喜欢的方式更改函数的顺序。
通常必须在您使用它的地方定义某些内容。 您可以针对不同的情况以不同的方式避免这种情况。
对于函数,只需在上面调用它的地方提供一个原型,一切都会好起来的。
int trol(int a, int b);
// use trol(int, int)
int trol(int a, int b) { }
如果您有两个函数a
和b
,并且它们相互调用并按以下顺序定义: a
, b
,那么您必须在a
的定义之上提供b
的原型。 a
的原型不是必需的,因为它是在上面定义的,它在b
内部使用。 那么编译器就没有问题了。
函数的另一种特殊情况是您可以使用 function 而不声明它,编译器将尝试从调用中推断签名。 这个答案很好地解释了我认为: 必须在 C 中声明 function 原型?
对于struct
,您可以通过提供前向声明在实际定义它们之前使用指向它们的指针(但您不能访问任何字段):
struct s;
// use s*'s
struct s { };
(上面的场景有利于递归数据结构,如链表和树;您可以在完全定义之前使用指向struct
的指针,因为任何类型的指针的大小都是恒定的。)
这很重要,因为如果编译器不知道 function 是什么 - 它会尝试“猜测”(创建具有匹配参数的默认int foo()
原型),如果你的调用不正确 - 你会有不匹配(构建错误,隐式转换,等等)。
在调用 function 之前(通过原型也就是前向声明)声明它是一种常见的做法(如果甚至不需要)。
对于具有可变参数列表的函数(如printf
),您必须有一个前向声明才能使它们正常工作。 例如,此代码将无法编译:
int foo(int a)
{
b(a);
b("hello", "kitty");
}
void b(int a, ...)
{
printf("%d", a);
}
但这 - 将:
#include <stdio.h>
int foo(int a)
{
return b(a);
}
int b(int a)
{
return printf("%d", a);
}
(带有关于隐式前向声明的警告)
因此,为了避免处理文件中对象的顺序 - 使用原型(前向声明)让编译器知道接下来的内容。
根据我的经验,C 中的所有内容都必须在引用之前用引用的“对象”编写。 我不认为这是特定于任何编译器的,但也许有些我还没有找到。 基本上,一切都必须是:
Object Declaration
...
Object Reference
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.