我在一个文件中定义了一个全局变量char buf[1024]
,在其他文件中声明它的正确性是什么? extern char buf[1024]
,extern char buf[]
或extern char *buf
?我发现extern char buf[]
的作品和extern char *buf
没有,但想知道更多的解释。
extern char buf []和extern char buf [1024]都可以。
在某些情况下,数组由指针实现,例如在两个函数之间传递参数。
当您将变量设置为extern时,您向编译器指示变量的符号(地址)将在另一个.o文件中找到 - (这在链接阶段完成)。
因此,当您将变量设置为extern时,您只需要提及名称,因为它将提供有关地址和大小的信息不是必需的
这是数组和指针可以互换的老问题。数组和指针不可互换:它们恰好恰好在大多数情况下,因为大多数时候你在表达式中使用数组名称,它会衰减成指针。
在Expert C Programming - Deep C Secrets中详细解释了在一个文件中定义为char数组并在另一个文件中声明为char指针的特定情况。见第4章。
数组的声明为您提供了一个数组,指针的声明为您提供了一个指针。不同之处在于数组是一个地址 - 第一个元素的地址 - 并且它不是可修改的l值,即它不能被赋值。另一方面,指针是保存地址的变量。
通常,上下文足以判断您是指变量的地址还是赋值中变量的内容。该声明
i = j;
是说将j
的内容存储在i
的地址中。在编译器行话中,i
被认为是l值,而j
是r值。编译器必须生成将j
的内存地址的内容写入i
的内存地址的代码。
考虑这些声明:
char a[1024];
char *a;
写a[i] = j;
会发生什么?
对于前一种情况,编译器将只选择a
内容的地址,其在数组中是第一个元素的地址;缩放i
,并将其加到基址。然后它会将存储j
的地址内容写入该地址。
对于后一种情况,它是完全不同的:编译器必须检查存储a
的内存位置,加载该内存位置的内容,使用THAT作为地址,并将j
的内容写入该地址。
如果在file1.c
中声明这样的字符数组:
char a[] = "Hello";
然后在file2
中定义
extern char *a;
然后,在a[0] = 'x';
中执行file2.c
将崩溃:因为你告诉编译器a
是一个指针,它将检查存储a
值的地址。实际上,这个地址持有'H'
的字符代码,但是编译器错误地将其解释为地址,并最终生成代码以将'x'
写入地址'H'
,如果你很幸运,它将使你的程序崩溃分段违规。
因此,这是声明和定义必须匹配的情况:如果您将其声明为数组,则将其定义为数组;如果您将其声明为指针,请将其定义为指针。您必须将buf
声明为其他文件中的字符数组。这些表格中的任何一种都是合法且等同的:
extern char buf[1024];
要么
extern char buf[];
可分配的全局char变量。让所有人都看得见:
// shared_header.h
extern char current_mode[];
定义,实例化和更新:
// main.c
#include "shared_header.h"
char current_mode[160];
int main(int argc, char * argv [])
{
strcpy(current_mode, "MODE_CONFIGURE");
int a = randomNumber(102);
strcpy(current_mode, "MODE_EXECUTE");
int b = do_foo(a);
// other stuff
strcpy(current_mode, "MODE_TEARDOWN");
// close up shop
}
阅读或更新:
// foo.c
#include "shared_header.h"
int do_foo(int a)
{
printf("Current mode is %s", current_mode);
if (a > 100) {
strcpy(current_mode, "MODE_EXECUTE_SPECIAL_CASE");
printf("Switching to mode %s", current_mode);
}
// do useful things
}