long long int vs. long int vs. int64_t in C++
在使用C ++类型特征时,我经历了一些奇怪的行为,并且将我的问题缩小到这个古怪的小问题,由于我不想留下任何可能引起误解的信息,因此我将作大量解释。
假设您有一个像这样的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <iostream> #include <cstdint> template <typename T> bool is_int64() { return false; } template <> bool is_int64<int64_t>() { return true; } int main() { std::cout <<"int:\t" << is_int64<int>() << std::endl; std::cout <<"int64_t:\t" << is_int64<int64_t>() << std::endl; std::cout <<"long int:\t" << is_int64<long int>() << std::endl; std::cout <<"long long int:\t" << is_int64<long long int>() << std::endl; return 0; } |
在使用GCC(以及32位和64位MSVC)的32位编译中,程序的输出为:
1 2 3 4 | int: 0 int64_t: 1 long int: 0 long long int: 1 |
但是,由64位GCC编译产生的程序将输出:
1 2 3 4 | int: 0 int64_t: 1 long int: 1 long long int: 0 |
这很奇怪,因为
1 2 3 4 5 6 | # if __WORDSIZE == 64 typedef long int int64_t; # else __extension__ typedef long long int int64_t; # endif |
在64位编译中,
解决这种情况非常简单:
1 2 3 4 | #if defined(__GNUC__) && (__WORDSIZE == 64) template <> bool is_int64<long long int>() { return true; } #endif |
但这是骇人听闻的技巧,而且扩展性不好(实体的实际功能,
我最初的想法是,由于C / C ++类型定义的工作方式,这是不可能的。没有一种方法可以为编译器指定基本数据类型的类型等效性,因为这是编译器的工作(允许这样做可能会破坏很多事情),而
我也不是很想在这里得到答案,因为这是一个超级骗局,我不怀疑任何人都不会关心这些示例的设计错误(这是否应该是社区Wiki?)。 。
附录:之所以使用部分模板专业化,而不是像下面这样的简单示例,是因为
1 2 3 4 5 6 7 8 | void go(int64_t) { } int main() { long long int x = 2; go(x); return 0; } |
就是说,由于
追加:到目前为止,唯一的答案是假设我想知道类型是否为64位。我不想误导人们以为我对此很在意,并且可能应该提供更多示例说明此问题在何处显现。
1 2 3 4 5 | template <typename T> struct some_type_trait : boost::false_type { }; template <> struct some_type_trait<int64_t> : boost::true_type { }; |
在此示例中,
另一个示例使用的是类似
1 2 3 4 5 6 7 8 9 | template <typename T> void same_type(T, T) { } void foo() { long int x; long long int y; same_type(x, y); } |
该示例无法编译,因为C ++(正确)看到类型不同。 g ++将无法编译,并显示以下错误:没有匹配的函数调用
我想强调指出,我理解为什么会这样,但是我正在寻找一种解决方法,它不会迫使我在各处重复执行代码。
您无需转到64位即可看到类似内容。在常见的32位平台上考虑
不难看出,没有解决方法可以在32位系统上使用
如果可以的话,对于
正确的解决方案是您的模板代码通常不应依赖于精确类型,而应依赖于该类型的属性。对于特定情况,整个
1 2 | long foo(long x); std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t); |
即,当重载
[编辑]
使用C ++ 11,我们现在有了一种标准的编写方式:
1 2 | long foo(long x); std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t); |
您是否想知道某个类型是否与int64_t相同,还是想知道某些东西是否为64位?根据您提出的解决方案,我认为您是在询问后者。在这种情况下,我会做类似的事情
1 2 | template<typename T> bool is_64bits() { return sizeof(T) * CHAR_BIT == 64; } // or >= 64 |
So my question is: Is there a way to tell the compiler that a long long int is the also a int64_t, just like long int is?
这是一个很好的问题,但我怀疑答案是否定的。
另外,
1
2
3
4
5
6 # if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
我相信这是libc。我怀疑你想更深入。
In both 32-bit compile with GCC (and with 32- and 64-bit MSVC), the
output of the program will be:
1
2
3
4 int: 0
int64_t: 1
long int: 0
long long int: 1
32位Linux使用ILP32数据模型。整数,long和指针均为32位。 64位类型是
Microsoft在"数据类型范围"中记录了范围。口语
However, the program resulting from a 64-bit GCC compile will output:
1
2
3
4 int: 0
int64_t: 1
long int: 1
long long int: 0
64位Linux使用
有一个
But this is horribly hackish and does not scale well (actual functions of substance, uint64_t, etc)...
是的,它变得更好。 GCC混合并匹配应该采用64位类型的声明,因此即使您遵循特定的数据模型,也很容易遇到麻烦。例如,以下内容导致编译错误,并告诉您使用
1 2 3 4 5 6 7 8 9 10 11 12 | #if __LP64__ typedef unsigned long word64; #else typedef unsigned long long word64; #endif // intel definition of rdrand64_step (http://software.intel.com/en-us/node/523864) // extern int _rdrand64_step(unsigned __int64 *random_val); // Try it: word64 val; int res = rdrand64_step(&val); |
结果是:
1 | error: invalid conversion from `word64* {aka long unsigned int*}' to `long long unsigned int*' |
因此,忽略
1 | typedef unsigned long long word64; |
然后,转到定义
1 | error: invalid conversion from `word64* {aka long long unsigned int*}' to `uint64_t*' |