C++ 中的 long long int 与 long int 与 int64_t
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4160945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
long long int vs. long int vs. int64_t in C++
提问by Travis Gockel
I experienced some odd behavior while using C++ type traits and have narrowed my problem down to this quirky little problem for which I will give a ton of explanation since I do not want to leave anything open for misinterpretation.
我在使用 C++ 类型特征时遇到了一些奇怪的行为,并将我的问题缩小到这个古怪的小问题,我将对此进行大量解释,因为我不想留下任何误解。
Say you have a program like so:
假设你有一个这样的程序:
#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;
}
In both 32-bit compile with GCC (and with 32- and 64-bit MSVC), the output of the program will be:
在使用 GCC(以及使用 32 位和 64 位 MSVC)的 32 位编译中,程序的输出将是:
int: 0
int64_t: 1
long int: 0
long long int: 1
However, the program resulting from a 64-bit GCC compile will output:
但是,由 64 位 GCC 编译生成的程序将输出:
int: 0
int64_t: 1
long int: 1
long long int: 0
This is curious, since long long int
is a signed 64-bit integer and is, for all intents and purposes, identical to the long int
and int64_t
types, so logically, int64_t
, long int
and long long int
would be equivalent types - the assembly generated when using these types is identical. One look at stdint.h
tells me why:
这很奇怪,因为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
In a 64-bit compile, int64_t
is long int
, not a long long int
(obviously).
在 64 位编译中,int64_t
is long int
,不是 a long long int
(显然)。
The fix for this situation is pretty easy:
这种情况的修复非常简单:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
But this is horribly hackish and does not scale well (actual functions of substance, uint64_t
, etc). 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?
但这是非常骇人听闻的,并且不能很好地扩展(substance 的实际功能uint64_t
等)。 所以我的问题是:有没有办法告诉编译器 along long int
也是 a int64_t
,就像long int
是一样?
My initial thoughts are that this is not possible, due to the way C/C++ type definitions work. There is not a way to specify type equivalence of the basic data types to the compiler, since that is the compiler's job (and allowing that could break a lot of things) and typedef
only goes one way.
我最初的想法是,由于 C/C++ 类型定义的工作方式,这是不可能的。没有一种方法可以为编译器指定基本数据类型的类型等效性,因为这是编译器的工作(并且允许这样做可能会破坏很多事情)并且typedef
只有一种方法。
I'm also not too concerned with getting an answer here, since this is a super-duper edge case that I do not suspect anyone will ever care about when the examples are not horribly contrived (does that mean this should be community wiki?).
我也不太关心在这里得到答案,因为这是一个超级骗子的边缘案例,我不怀疑任何人会在示例不是精心设计的时候关心(这是否意味着这应该是社区维基?) .
Append: The reason why I'm using partial template specialization instead of an easier example like:
附加:我使用部分模板特化而不是更简单的例子的原因,如:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
is that said example will still compile, since long long int
is implicitly convertible to an int64_t
.
是说该示例仍将编译,因为它long long int
可以隐式转换为int64_t
.
Append: The only answer so far assumes that I want to know if a type is 64-bits. I did not want to mislead people into thinking that I care about that and probably should have provided more examples of where this problem manifests itself.
附加:目前唯一的答案是假设我想知道类型是否为 64 位。我不想误导人们认为我关心这个,并且可能应该提供更多关于这个问题表现出来的例子。
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
In this example, some_type_trait<long int>
will be a boost::true_type
, but some_type_trait<long long int>
will not be. While this makes sense in C++'s idea of types, it is not desirable.
在此示例中,some_type_trait<long int>
将是boost::true_type
,但some_type_trait<long long int>
不会是。虽然这在 C++ 的类型概念中是有道理的,但这是不可取的。
Another example is using a qualifier like same_type
(which is pretty common to use in C++0x Concepts):
另一个例子是使用像这样的限定符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);
}
That example fails to compile, since C++ (correctly) sees that the types are different. g++ will fail to compile with an error like: no matching function call same_type(long int&, long long int&)
.
该示例无法编译,因为 C++(正确地)认为类型不同。g++ 将无法编译并出现如下错误: no matching function call same_type(long int&, long long int&)
。
I would like to stress that I understand whythis is happening, but I am looking for a workaround that does not force me to repeat code all over the place.
我想强调的是,我理解为什么会发生这种情况,但我正在寻找一种不会强迫我到处重复代码的解决方法。
采纳答案by MSalters
You don't need to go to 64-bit to see something like this. Consider int32_t
on common 32-bit platforms. It might be typedef
'ed as int
or as a long
, but obviously only one of the two at a time. int
and long
are of course distinct types.
您无需转到 64 位即可看到此类内容。考虑int32_t
常见的 32 位平台。它可能被typedef
'ed asint
或 as a long
,但显然一次只能是两者之一。int
并且long
当然是不同的类型。
It's not hard to see that there is no workaround which makes int == int32_t == long
on 32-bit systems. For the same reason, there's no way to make long == int64_t == long long
on 64-bit systems.
不难看出,int == int32_t == long
在 32 位系统上没有解决方法。出于同样的原因,无法long == int64_t == long long
在 64 位系统上进行制作。
If you could, the possible consequences would be rather painful for code that overloaded foo(int)
, foo(long)
and foo(long long)
- suddenly they'd have two definitions for the same overload?!
如果可以,对于重载 的代码,可能的后果将是相当痛苦的foo(int)
,foo(long)
并且foo(long long)
-突然之间,它们对同一个重载有两个定义?!
The correct solution is that your template code usually should not be relying on a precise type, but on the properties of that type. The whole same_type
logic could still be OK for specific cases:
正确的解决方案是您的模板代码通常不应该依赖于精确的类型,而应该依赖于该类型的属性。same_type
对于特定情况,整个逻辑仍然可以:
long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);
I.e., the overload foo(int64_t)
is not defined when it's exactlythe same as foo(long)
.
即,过载foo(int64_t)
时,它没有定义完全相同一样foo(long)
。
[edit] With C++11, we now have a standard way to write this:
[编辑] 使用 C++11,我们现在有一个标准的方法来写这个:
long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);
回答by Logan Capaldo
Do you want to know if a type is the same type as int64_t or do you want to know if something is 64 bits? Based on your proposed solution, I think you're asking about the latter. In that case, I would do something like
您想知道某个类型是否与 int64_t 类型相同,还是想知道某个类型是否为 64 位?根据您提出的解决方案,我认为您是在问后者。在那种情况下,我会做类似的事情
template<typename T>
bool is_64bits() { return sizeof(T) * CHAR_BIT == 64; } // or >= 64
回答by jww
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?
所以我的问题是:有没有办法告诉编译器 long long int 也是 int64_t,就像 long int 一样?
This is a good question or problem, but I suspect the answer is NO.
这是一个很好的问题,但我怀疑答案是否定的。
Also, a long int
may not be a long long int
.
此外, along int
可能不是 a long long int
。
# if __WORDSIZE == 64 typedef long int int64_t; # else __extension__ typedef long long int int64_t; # endif
# if __WORDSIZE == 64 typedef long int int64_t; # else __extension__ typedef long long int int64_t; # endif
I believe this is libc. I suspect you want to go deeper.
我相信这是 libc。我怀疑你想更深入。
In both 32-bit compile with GCC (and with 32- and 64-bit MSVC), the output of the program will be:
int: 0 int64_t: 1 long int: 0 long long int: 1
在使用 GCC(以及使用 32 位和 64 位 MSVC)的 32 位编译中,程序的输出将是:
int: 0 int64_t: 1 long int: 0 long long int: 1
32-bit Linux uses the ILP32 data model. Integers, longs and pointers are 32-bit. The 64-bit type is a long long
.
32 位 Linux 使用 ILP32 数据模型。整数、长整数和指针是 32 位的。64 位类型是long long
.
Microsoft documents the ranges at Data Type Ranges. The say the long long
is equivalent to __int64
.
Microsoft 在Data Type Ranges 中记录范围。该说long long
相当于__int64
。
However, the program resulting from a 64-bit GCC compile will output:
int: 0 int64_t: 1 long int: 1 long long int: 0
但是,由 64 位 GCC 编译生成的程序将输出:
int: 0 int64_t: 1 long int: 1 long long int: 0
64-bit Linux uses the LP64
data model. Longs are 64-bit and long long
are 64-bit. As with 32-bit, Microsoft documents the ranges at Data Type Rangesand long long is still __int64
.
64 位 Linux 使用LP64
数据模型。Longs 是 64 位的,并且long long
是 64 位的。与 32 位一样,Microsoft 将范围记录在Data Type Ranges 中,而 long long 仍然是__int64
.
There's a ILP64
data model where everything is 64-bit. You have to do some extra work to get a definition for your word32
type. Also see papers like 64-Bit Programming Models: Why LP64?
有一个ILP64
数据模型,其中一切都是 64 位。您必须做一些额外的工作才能为您的word32
类型获得定义。另请参阅64 位编程模型:为什么是 LP64?
But this is horribly hackish and does not scale well (actual functions of substance, uint64_t, etc)...
但这是非常骇人听闻的,并且不能很好地扩展(substance、uint64_t 等的实际功能)......
Yeah, it gets even better. GCC mixes and matches declarations that are supposed to take 64 bit types, so its easy to get into trouble even though you follow a particular data model. For example, the following causes a compile error and tells you to use -fpermissive
:
是的,它变得更好了。GCC 混合和匹配应该采用 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);
It results in:
结果是:
error: invalid conversion from `word64* {aka long unsigned int*}' to `long long unsigned int*'
So, ignore LP64
and change it to:
因此,忽略LP64
并将其更改为:
typedef unsigned long long word64;
Then, wander over to a 64-bit ARM IoT gadget that defines LP64
and use NEON:
然后,转到定义LP64
和使用 NEON的 64 位 ARM IoT 小工具:
error: invalid conversion from `word64* {aka long long unsigned int*}' to `uint64_t*'