我最近在一些正在开发的大型程序中发现了一个烦人的问题; 我想了解如何以最佳方式解决它.我将代码剪切到以下最小的示例.
#include <iostream>
using std::cin;
using std::cout;
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
int main()
{
int choice;
cout << "How much stuff do you want?\n";
cin >> choice;
int stuff = (choice < 20) ? MagicNumbers::SMALL : MagicNumbers::BIG; // PROBLEM!
cout << "You got " << stuff << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用-O0或-O1进行编译时,我在gcc 4.1.2中遇到链接错误,但在使用-O2或-O3进行编译时一切正常.无论优化选项如何,它都可以使用MS Visual Studio 2005很好地链接.
test.cpp :(.text + 0xab):未定义的引用`MagicNumbers :: SMALL'
test.cpp :(.text + 0xb3):未定义引用`MagicNumbers :: BIG'
我查看了中间汇编代码,是的,非优化代码将SMALL和BIG视为外部int变量,而优化后的代码使用实际数字.以下每个更改都解决了以下问题:
常量使用enum而不是int: enum {SMALL = 10}
在每次使用铸常数(任一个):(int)MagicNumbers::SMALL或(int)MagicNumbers::BIG或甚至MagicNumbers::SMALL + 0
使用宏: #define SMALL 10
不使用选择运算符: if (choice < 20) stuff = MagicNumbers::SMALL; else stuff = MagicNumbers::BIG;
我最喜欢第一个选项(但是,它并不理想,因为我们实际上对这些常量使用uint32_t而不是int,而enum与int同义).但我真正想问的是:它的错误是什么?
我不应该理解静态积分常数是如何工作的吗?
我应该责怪gcc并希望修复(或者最新版本已经有修复,或者可能有一个模糊的命令行参数使这项工作)?
同时,我只是通过优化编译我的代码,调试很痛苦:-O3
静态数据成员不是给定类类型的对象的一部分; 它们是独立的对象.因此,静态数据成员的声明不被视为定义.数据成员在类范围内声明,但定义在文件范围内执行.这些静态成员具有外部链接.
你只是声明那些常量,即使你正在初始化它们.您仍然需要在命名空间范围内定义它们:
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
const int MagicNumbers::BIG;
const int MagicNumbers::SMALL;
Run Code Online (Sandbox Code Playgroud)
这将摆脱链接错误.
尽管有传统的建议,我发现static const int ...总是让我头疼而不是好老enum { BIG = 100, SMALL = 10 };.并且随着C++ 11提供强类型的枚举,我现在使用的原因更少static const int ....