C语言中的共享全局变量

89

我该如何创建在C中共享的全局变量?如果将其放在头文件中,则链接器会抱怨变量已经定义。难道唯一的方法是在我的一个C文件中声明变量,并在想使用它的所有其他C文件的顶部手动添加extern吗?这听起来不太理想。


在你的源代码内共享?将 extern 声明放在一个头文件中,并将定义放在另一个(单一的)源代码文件中。当然,它们在你的进程线程之间是共享的。要进行进程间数据共享,请使用 IPC 机制(共享内存、管道)。 - Hernán
1
请参阅C语言中的extern变量是什么? - Jonathan Leffler
2
可能是如何在不同的.c文件之间共享变量?的重复问题。 - 7hi4g0
7个回答

99

在一个头文件中 (shared.h):

extern int this_is_global;
在每个想要使用这个全局符号的文件中,都需要包含包含extern声明的头文件:
#include "shared.h"

为了避免多个链接器定义,你的全局符号只能在编译单元中存在一个声明(例如:shared.cpp):

/* shared.cpp */
#include "shared.h"
int this_is_global;

你有没有任何偏好的参考资料来了解更多关于IPC机制的知识? - NickO
7
请更加强调“只需要在全局符号中声明一次……”这句话。我之前没有理解清楚,结果在所有想要使用全局变量的C文件中都声明了一遍 :( - AntonioCS

71

在头文件中使用 extern 关键字进行声明。 并且在某个 C 文件的全局作用域中不使用 extern 进行声明。


1
我们能否在那个*.c文件的头文件中声明它呢? - Geremia

22

在头文件中

#ifndef SHAREFILE_INCLUDED
#define SHAREFILE_INCLUDED
#ifdef  MAIN_FILE
int global;
#else
extern int global;
#endif
#endif

在你想要全局变量存在的文件中:

#define MAIN_FILE
#include "share.h"

在需要使用外部版本的其他文件中:

#include "share.h"

啊,这就是我一段时间前想到的解决方案——我忘记了MAIN_FILE预处理器变量。不过我认为我更喜欢当前被接受的答案。 - Claudiu

16

你将声明放在头文件中,例如:

 extern int my_global;
在你的一个 .c 文件中,你在全局范围内定义了它。
int my_global;

所有想要访问my_global的.c文件都会包含带有extern的头文件。


6

如果你在C和C++之间共享代码,请记得将以下内容添加到shared.h文件中:

#ifdef __cplusplus
extern "C" {
#endif

extern int my_global;
/* other extern declarations ... */

#ifdef __cplusplus
}
#endif

2

有一种更简洁的方式,只需要一个头文件,因此更容易维护。 在全局变量的头文件中,每个声明都要以关键字(我使用common)为前缀,然后在一个源文件中这样包含它:

#define common
#include "globals.h"
#undef common

以及像这样的任何其他源文件

#define common extern
#include "globals.h"
#undef common

请确保不要在globals.h文件中初始化任何变量,否则链接器仍会抱怨,因为初始化的变量即使使用extern关键字也不会被视为外部变量。global.h文件类似于以下内容:

#pragma once
common int globala;
common int globalb;
etc.

这似乎适用于任何类型的声明。当然,不要在 #define 中使用常见的关键字。


如果你想避免在包含globals.h时每次定义common,你也可以在头文件中添加#ifndef common #define common extern #endif。唯一的注意点是common不会自动未定义。 - GDavid

0

有一种更优雅的方法来创建全局变量。

只需在“.c”源文件中将变量声明为静态,并创建set/get函数即可。

下面的示例我用于在内存分配测试期间覆盖malloc,realloc和free函数。

示例:

memory-allocator.h

#ifndef MEMORY_ALLOCATOR_H_
#define MEMORY_ALLOCATOR_H_

#include <stddef.h>

void std_set_memory_allocators(void *(*malloc)(size_t size),
                               void *(realloc)(void *ptr, size_t size),
                               void (*free)(void *ptr));

void std_set_reset_allocators();

void *std_malloc(size_t size);

void *std_realloc(void *ptr, size_t size);

void std_free(void *ptr);

#endif  // MEMORY_ALLOCATOR_H_

memory-allocator.c

#include "memory-allocator.h"

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    void *(*malloc)(size_t size);
    void *(*realloc)(void *ptr, size_t size);
    void (*free)(void *ptr);
} StdMemoryAllocator;

StdMemoryAllocator memory_allocators = {&malloc, &realloc, &free};

void std_set_memory_allocators(void *(*malloc)(size_t size),
                               void *(realloc)(void *ptr, size_t size),
                               void (*free)(void *ptr)) {
    memory_allocators.malloc = malloc;
    memory_allocators.realloc = realloc;
    memory_allocators.free = free;
}

void std_set_reset_allocators() {
    memory_allocators.malloc = malloc;
    memory_allocators.realloc = realloc;
    memory_allocators.free = free;
}

void *std_malloc(size_t size) {
    return memory_allocators.malloc(size);
}

void *std_realloc(void *ptr, size_t size) {
    return memory_allocators.realloc(ptr, size);
}

void std_free(void *ptr) {
    memory_allocators.free(ptr);
}

结构体 static struct StdMemoryAllocator_s memory_allocators 在应用程序启动时自动启动,并指向默认的 C 内存分配器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接