长int vs.长int vs. int64_t in C ++
题
我在使用C ++类型特征时经历了一些奇怪的行为,并将我的问题缩小到这个古怪的小问题,因为我不想为误解而留下任何开放的解释,因此我会提供大量的解释。
说您有这样的程序:
#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位中,该程序的输出将为:
int: 0
int64_t: 1
long int: 0
long long int: 1
但是,由64位GCC编译产生的程序将输出:
int: 0
int64_t: 1
long int: 1
long long int: 0
这很好奇,因为 long long int
是签名的64位整数,出于所有意图和目的,与 long int
和 int64_t
类型,因此从逻辑上讲, int64_t
, long int
和 long long int
将是等效类型 - 使用这些类型时生成的组件是相同的。一看 stdint.h
告诉我为什么:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
在64位编译中 int64_t
是 long int
, ,不是 long long int
(明显地)。
解决这种情况非常容易:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
但这真是可怕的刺,并且不缩放不错(实质的实际功能, uint64_t
, , ETC)。 所以我的问题是: 有没有办法告诉编译器 long long int
也是一个 int64_t
, , 就像 long int
是?
我最初的想法是,由于C/C ++类型定义的工作方式,这是不可能的。没有一种方法可以指定基本数据类型与编译器的类型等效性,因为这是编译器的作业(允许可能破坏很多事情)和 typedef
只有一种方式。
我也不太关心在这里得到答案,因为这是一个超级淘汰的案例,我不怀疑有人会在乎何时没有可怕的人为(这意味着这应该是社区Wiki)? 。
附加: :为什么我使用部分模板专业化而不是一个更轻松的示例,例如:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
是那个示例仍然会编译,因为 long long int
隐式转换为 int64_t
.
附加: :到目前为止,唯一的答案是我想知道一种类型是否为64位。我不想误导人们以为我关心这一点,并且可能应该提供更多有关此问题自我出现的例子。
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
在此示例中 some_type_trait<long int>
将是一个 boost::true_type
, , 但 some_type_trait<long long int>
不会是。尽管这在C ++的类型概念中是有意义的,但这是不可取的。
另一个示例是使用类似的预选赛 same_type
(在C ++ 0x概念中使用非常常见):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
该示例无法编译,因为C ++(正确)看到类型不同。 G ++将无法通过错误的错误进行编译:无匹配函数调用 same_type(long int&, long long int&)
.
我想强调我了解 为什么 这正在发生,但是我正在寻找一个解决方法,不会迫使我在整个地方重复代码。
解决方案
您无需去64位即可看到这样的东西。考虑 int32_t
在常见的32位平台上。有可能 typedef
'ed as int
或作为一个 long
, ,但显然一次只有两个。 int
和 long
当然是不同的类型。
不难看到没有解决方法 int == int32_t == long
在32位系统上。出于同样的原因,没有办法 long == int64_t == long long
在64位系统上。
如果可以的话,可能的后果对于超负荷的代码会很痛苦 foo(int)
, foo(long)
和 foo(long long)
- 突然,他们有两个定义的同一超载?
正确的解决方案是,您的模板代码通常不应依赖于精确的类型,而应依靠该类型的属性。整体 same_type
对于特定情况,逻辑仍然可以是可以的:
long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);
即,超负荷 foo(int64_t)
当它是什么时候定义 确切地 与 foo(long)
.
编辑]使用C ++ 11,我们现在有一种标准的方式来编写以下方式:
long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);
其他提示
您想知道类型是否与INT64_T相同还是想知道64位的类型?根据您提出的解决方案,我认为您正在询问后者。在这种情况下,我会做类似的事情
template<typename T>
bool is_64bits() { return sizeof(T) * CHAR_BIT == 64; } // or >= 64
因此,我的问题是:有没有办法告诉编译器,长长的int也是一个int64_t,就像long int一样?
这是一个很好的问题或问题,但我怀疑答案是否定的。
也 long int
可能不是 long long int
.
# if __WORDSIZE == 64 typedef long int int64_t; # else __extension__ typedef long long int int64_t; # endif
我相信这是libc。我怀疑你想更深入。
在使用GCC(以及32位和64位MSVC)编译的32位中,该程序的输出将为:
int: 0 int64_t: 1 long int: 0 long long int: 1
32位Linux使用ILP32数据模型。整数,渴望和指针为32位。 64位类型是 long long
.
Microsoft记录了范围 数据类型范围. 。说 long long
等同于 __int64
.
但是,由64位GCC编译产生的程序将输出:
int: 0 int64_t: 1 long int: 1 long long int: 0
64位Linux使用 LP64
数据模型。渴望是64位, long long
是64位。与32位一样,Microsoft记录了范围 数据类型范围 长时间仍然 __int64
.
有个 ILP64
数据模型的所有内容均为64位。您必须做一些额外的工作才能为您的定义 word32
类型。也可以看到像 64位编程模型:为什么要LP64?
但这是可怕的骇人听闻,并且不能很好地扩展(实质,UINT64_T等的实际功能)...
是的,它变得更好。海湾合作委员会的混音和匹配声明应该需要64位类型,因此即使您遵循特定的数据模型,也很容易陷入麻烦。例如,以下会导致编译错误,并告诉您使用 -fpermissive
:
#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);
它导致:
error: invalid conversion from `word64* {aka long unsigned int*}' to `long long unsigned int*'
所以,忽略 LP64
并将其更改为:
typedef unsigned long long word64;
然后,漫步到一个定义的64位手臂IoT小工具 LP64
并使用霓虹灯:
error: invalid conversion from `word64* {aka long long unsigned int*}' to `uint64_t*'