简体   繁体   English

scanf()与C ++枚举

[英]scanf() with C++ enums

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 . 问题是c ++中的enum不一定是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* . 一种解决方案就是将&cfgint* However this will not catch cases where the compiler had decided to allocate something other than int to the enum . 但是,这不会捕获编译器决定在enum分配int以外的东西的情况。

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: 现在使用scanf如下:

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. 这不是“生产质量”的东西,你添加的越多 - 维护就越困难。

If you have a modern compiler like vs2010 you can specify the size of the enum elements 如果你有像vs2010这样的现代编译器,你可以指定枚举元素的大小

enum class ConfigOption: unsigned int {CONFIG_1=1, CONFIG_2=2, CONFIG_3=3};

its new in C++0x 它在C ++ 0x中的新功能

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). 我的解决方案是将枚举强制到最小尺寸。这就是微软在他们的DirectX头文件中为他们的枚举所做的事情(我不得不承认这是一个很好的技巧)。

They enforced the size of the enum to be equal to an int by adding a dummy enum like this: 他们通过添加如下虚拟枚举来强制枚举的大小等于int:

typedef enum 
{
  fooo = 1,
  baar = 2,
  ___Force32Bit = ~0UL
} MyEnum;

Now the enum will always be at least the size of an int. 现在枚举总是至少是int的大小。

If you want to you can take this over the top.. This one forces the size of the enum to a long long: 如果你愿意,你可以把它放在顶部..这个强迫enum的大小很长:

typedef enum 
{
  fooo = 1,
  baar = 2,
  ___Force64Bit = ~0ULL
} MyEnum;

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. 如果你从32位到64位代码,你可能需要调整代码,但通常在这些情况下你必须检查代码的某些部分,所以没有大问题。

Btw - sorry for the C-code, I know the question was tagged as C++, but I'm a C-guys :-) 顺便说一句 - 对不起C代码,我知道这个问题被标记为C ++,但我是C-guys :-)

Why not just read it as an actual int ? 为什么不把它作为一个实际的int读取?

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 };
ConfigOption cfg1;

int i;
sscanf(s, "%d", &i);
cfg1 = i;

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). 这样你就可以进行更全面的有效性检查(例如测试读取整数是否在你的enum类型范围内)。

(Of course, if you're at all concerned about detecting errors, for simple parsing like this, you should be using strtol or strtoul instead of sscanf .) (当然,如果您一直担心检测错误,对于这样的简单解析,您应该使用strtolstrtoul而不是sscanf 。)

You could try using boost::lexical_cast , or if you aren't using boost and don't want to start using it for just this case, you could just write a simplified version of that yourself. 您可以尝试使用boost::lexical_cast ,或者如果您不使用boost并且不想在这种情况下开始使用它,您可以自己编写一个简化版本。 For an example take a look at this SO answer . 举个例子来看看这个SO答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM