我正在尝试在 C(不是 C++)的仅标头库中实现一个全局单例变量。所以在这个论坛和其他地方搜索之后,我发现了我在这里适应 C 的 Meyer 单例的一个变体:
/* File: sing.h */
#ifndef SING_H
#define SING_H
inline int * singleton()
{
static int foo = 0;
return &foo;
}
#endif
请注意,我正在返回一个指针,因为 C 在 C++ 中缺少 & 引用,所以我必须解决它。
好的,现在我要测试它,所以这里是一个简单的测试代码:
/* File: side.h */
#ifndef SIDE_H
#define SIDE_H
void side();
#endif
/*File: side.c*/
#include "sing.h"
#include <stdio.h>
void side()
{
printf("%d\n",*(singleton()));
}
/*File: main.c*/
#include "sing.h"
#include "side.h"
#include <stdio.h>
int main(int argc, char * argv[])
{
/* Output default value - expected output: 0 */
printf("%d\n",*(singleton()));
*(singleton()) = 5;
/* Output modified value - expected output: 5 */
printf("%d\n",*(singleton()));
/* Output the same value from another module - expected output: 5*/
side();
return 0;
}
在 C 模式下的 MSVC 中编译和运行良好(也在 C++ 模式下,但这不是主题)。但是,在 gcc 中,它输出两个警告(警告:'foo' 是静态的,但在非静态的内联函数 'singleton' 中声明),并生成一个可执行文件,然后当我尝试运行它时会出现段错误。警告本身对我来说有点道理(事实上,我很惊讶我在 MSVC 中没有得到它),但是 segfault 暗示了 gcc 永远不会将 foo 编译为静态变量的可能性,使其成为局部变量stack 然后返回该变量的过期堆栈地址。
我尝试将单例声明为extern inline
,它在 MSVC 中编译并运行良好,导致 gcc 中的链接器错误(同样,我不抱怨链接器错误,这是合乎逻辑的)。我也尝试过static inline
(在 MSVC 和 gcc 中都编译得很好,但可以预见的是在第三行运行时输出错误,因为 side.c 翻译单元现在有自己的单例副本。
那么,我在 gcc 中做错了什么?我在 C++ 中没有这些问题,但在这种情况下我不能使用 C++,它必须是直接的 C 解决方案。
我还可以接受任何其他形式的单例实现,这些单例实现在 gcc 和 MSVC 中的纯 C 中的纯标头库中工作。