scanf() 与 C++枚举
以下是我们代码库中的典型情况。
enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 }
ConfigOption cfg1, cfg2;
sscanf(s, "%d", &cfg1);
这是一个内部使用的模拟软件。未分发。易于维护和正确性很重要。可移植性和用户界面——并非如此。
问题是 C++ 中的 enum
不一定是 int
。因此,我们会收到编译器警告,并且在使用不同的编译器或启用优化时可能会出现不正确的行为。
一种解决方案是将 &cfg
转换为 int*
。但是,这不会捕获编译器决定将 int
以外的内容分配给 enum
的情况。
所以我建议了以下解决方案:
template<typename T> inline
int& eint(T& enum_var) {
assert(sizeof(T) == sizeof(int));
return (int&)enum_var;
}
现在使用 scanf
如下:
sscanf(s, "%d", &eint(cfg1));
我很想听到针对上述问题的意见和其他(更好)解决方案。 请记住,目标之一是保持代码简单。这不是“生产质量”的东西,添加的越多,维护就越困难。
The following is a typical situation in our codebase.
enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 }
ConfigOption cfg1, cfg2;
sscanf(s, "%d", &cfg1);
This is an internally used simulation software. Not distributed. Ease of maintenance and correctness are important. Portability and user interface -- not really.
The trouble is enum
in C++ is not necessarily an int
. So we get a compiler warning, and may get incorrect behavior when using a different compiler or when optimizations are enabled.
One solution is just to cast &cfg
to int*
. However this will not catch cases where the compiler had decided to allocate something other than int
to the enum
.
So I suggested the following solution:
template<typename T> inline
int& eint(T& enum_var) {
assert(sizeof(T) == sizeof(int));
return (int&)enum_var;
}
And now one uses scanf
as follows:
sscanf(s, "%d", &eint(cfg1));
I would love to hear opinions and other (better) solutions to the above problem.
Keep in mind that one of the goals is to keep the code simple. This is not 'production-quality' stuff and the more you add -- the more difficult maintenance becomes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
枚举元素的大小
如果您有像 vs2010 这样的现代编译器,您可以指定C++0x 中新的
If you have a modern compiler like vs2010 you can specify the size of the enum elements
its new in C++0x
我的解决方案是强制枚举到最小大小。这就是 Microsoft 在 DirectX 头文件中对其枚举所做的事情(我不得不承认这是一个很好的技巧)。
他们通过添加一个虚拟枚举来强制枚举的大小等于 int,如下所示:
现在枚举将始终至少等于 int 的大小。
如果你愿意,你可以把它放在上面。这个强制枚举的大小很长:
我知道,这不是一个超级干净的解决方案。我认为这样的解决方案不存在,并且到目前为止,强制执行最小尺寸对我来说效果很好。如果从 32 位代码转到 64 位代码,您可能需要调整代码,但通常在这些情况下您必须检查代码的某些部分,所以没有什么大问题。
顺便说一句 - 抱歉 C 代码,我知道问题被标记为 C++,但我是 C 人:-)
My solution would be to force the enum to a minimum size.. That's what Microsoft did for their enums in their DirectX headerfiles (a nice trick I have to admit).
They enforced the size of the enum to be equal to an int by adding a dummy enum like this:
Now the enum will always be at least the size of an int.
If you want to you can take this over the top.. This one forces the size of the enum to a long long:
I know, it is not a super clean solution. I think such a solution does not exist and enforcing a minimum size worked well for me so far. You may have to adjust the code if you go from 32 to 64 bit code, but usually in these situations you have to review some parts of the code anyway, so no big issue.
Btw - sorry for the C-code, I know the question was tagged as C++, but I'm a C-guys :-)
为什么不把它当作一个实际的
int
来读取呢?这样您也可以进行更全面的有效性检查(例如测试读取的整数是否在您的
enum
类型的范围内)。(当然,如果您非常关心检测错误,对于像这样的简单解析,您应该使用
strtol
或strtoul
而不是sscanf
代码>.)Why not just read it as an actual
int
?And that way you can do more comprehensive validity checks too (such as testing that the read integer is within the range of your
enum
type).(Of course, if you're at all concerned about detecting errors, for simple parsing like this, you should be using
strtol
orstrtoul
instead ofsscanf
.)您可以尝试使用
boost::lexical_cast
,或者如果您没有使用boost
并且不想在这种情况下开始使用它,您可以自己编写一个简化版本。例如,请查看这个答案 。You could try using
boost::lexical_cast
, or if you aren't usingboost
and don't want to start using it for just this case, you could just write a simplified version of that yourself. For an example take a look at this SO answer.