字符串作为常量的效率
Efficiency of strings as constants?
我是一个相对的C/C++noob,但在C#和其他一些语言方面经验丰富,目前正在用C++构建游戏引擎。
对于输入系统(键/鼠标/操纵杆),我有一个想法,使用字符串文字来简化特定于游戏的输入事件的配置,而不是枚举。但我不完全确定C编译器会如何优化它——每次逐个字符串进行比较可能效率很低。
以下是基本思想-从设备事件到"游戏特定事件"的映射将在一个std::map中,其中包含int/enum键和const-char*值:
Mappings[ KEY_X ] = "Jump";
Mappings[ KEY_Y ] = "Shoot";
Mappings[ MOUSE_1 ] = "Shoot";
这些可以是硬编码的,从配置文件加载,等等(字符串将简化解析和保存,以及添加新的事件类型)
然后在游戏中,我可以只处理特定于游戏的事件:
if ( IsDown( "Jump" ) ) {
}
if ( IsSinglePress( "Shoot" ) ) {
}
问题是,我所有的字符串文字和constchar*都会被神奇地优化掉,并最终像枚举或整数常量一样高效吗?例如
if ( IsDown( GAMEKEY_SHOOT ) ) {
// ...
}
还是会进行字符串比较等。?我希望编译器能看到相同字符串文字的实例,将其存储一次,并始终使用一个指针值,但不确定。
如果所有字符串常量都在同一个文件中,它们可能会折叠到同一个内存位置。如果它们在几个单独编译的文件中,或者如果你动态地读取它们,它们就不会是。
由于您使用的是C(++),因此可以通过两种方式比较字符串(您在问题中没有对此做任何说明):指针标识(==
)或逐字符比较(strncmp
)。如果你在做前者,它是非常不可靠的,因为它取决于编译器的变化无常(在第二种情况下肯定会失败);如果是后者,那么您知道将进行字符串比较。
省得头疼,用你已经知道的正确方法来做:枚举或常量。在输入/输出时转换一次,然后您可以在内部将它们作为数字处理,这既快速又安全。
您提到过几次枚举和字符串之间的转换。以下是我的做法。(我认为这个想法应该归功于gcc。)用创建一个类似action.def的文件
ENUM(Jump)
ENUM(Shoot)
在头文件中,定义如下的枚举
#define ENUM(a) a,
Enum Actions {
#include "action.def"
};
#undef ENUM
在需要将枚举成员映射到字符串的.cpp文件中,执行以下
struct EnumMap {
int value;
const char * name;
}
#define ENUM(a) { (int) a, #a },
struct EnumMap {
#include "action.def"
} ActionMap[];
#undef ENUM
然后,您的代码使用ActionMap[]将枚举值转换为字符串并返回。
无论如何,多次写出相同的字符串文字都很容易出错——如果您错误地键入了其中一个呢?
如果你使用全局变量,你可以确保它们有相同的地址,因为你指的是完全相同的变量:
char const * const Jump = "Jump";
(或在标头中声明并在单个.cpp中初始化实际字符串值)
并用作:
Mappings[ KEY_X ] = Jump;
...
if ( IsDown( Jump ) ) {
...
我不会假装这是一种很棒的风格(事实并非如此),如果你只是想在枚举和字符串表示之间建立一个内置链接,有更好的方法可以获得它
就标准而言,编译器可能会也可能不会使相同字符串文字的各个实例指向内存的相同位置
是否所有字符串文字都是不同的(即存储在不重叠的对象中)是实现定义的。
(C++11,§2.14.5¶12)
此外,如果值是动态分配的,来自某个缓冲区。。。它们肯定有不同于字符串文字的地址;因此,检查一个是否等于另一个的唯一合理方法是比较字符串的字节(以类似strcmp
的方式),这显然比指针比较慢。
此外,我不认为在这些设置中使用字符串有什么意义:只需使用enum
s,它的执行速度至少同样快(可能更快),而且它不太容易出错(如果你写错了枚举值,就会出现编译错误,如果你在字符串常量中键入了错误,它会被默默接受)。
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 什么时候在C++中返回常量引用是个好主意
- 代理对象的常量正确性
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 通过多个头文件使用常量变量
- 在cuda线程之间共享大量常量数据
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 是默认情况下分配给char数组常量的值
- 私有类型的静态常量成员
- 类似枚举的计算常量
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 为什么我可以通过引用修改常量返回
- 如何创建长度由常量参数指定的数组
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- 隐式常量/非常量运算符布尔
- 字符串作为常量的效率
- 为什么有或没有常量修饰符会使效率相差 4 倍