C语言中的long long int vs. long int vs.int64_t [英] long long int vs. long int vs. int64_t in C++

查看:323
本文介绍了C语言中的long long int vs. long int vs.int64_t的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用C ++类型特征时,我经历了一些奇怪的行为,并且将我的问题缩小到这个古怪的小问题,由于我不想留下任何可能引起误解的地方,因此我将作大量解释。



假设您有一个像这样的程序:

  #include< iostream> 
#include< cstdint>

模板< typename T>
bool is_int64(){return false; }

模板<>
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;

返回0;
}

在32位使用GCC(以及32-和64-位MSVC),程序的输出将为:

  int:0 
int64_t:1
long int:0
long long int:1

但是,该程序由64位GCC编译将输出:

  int:0 
int64_t:1
长整数:1
long long int:0

这很奇怪,因为 long long int 是一个带符号的64位整数,从所有意图和目的出发,它均与 long int int64_t 类型,因此从逻辑上讲, int64_t long int long long int 将是等效类型-使用这些类型时生成的程序集是相同的。看看 stdint.h 告诉我为什么:

 #如果__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 define(__ GNUC__)& ;& (__WORDSIZE == 64)
模板<>
bool is_int64< long long int>(){return true; }
#endif

但这是骇人听闻的,不能很好地扩展(实际功能实质, uint64_t 等)。 所以我的问题是:有没有办法告诉编译器 int 也是 int64_t ,就像 long int 是吗?






<我最初的想法是,由于C / C ++类型定义的工作方式,这是不可能的。没有一种方法可以指定基本数据类型与编译器的类型等效,因为这是编译器的工作(并且可能会破坏很多事情)和 typedef



我也不是很担心在这里得到答案,因为这是一个超级骗子,我不怀疑有人会关心示例不是精心设计的(这是否应该是社区Wiki?)。






附加:之所以使用部分模板专业化,而不是像下面这样的简单示例,是因为

  void go( int64_t){} 

int main()
{
long long int x = 2;
go(x);
返回0;
}

是说该示例仍然可以编译,因为 long long int 可隐式转换为 int64_t






追加:到目前为止,唯一的答案是假设我想知道类型是否为64位。我不想误导人们以为我对此很在意,可能应该提供更多示例说明此问题的所在。

  template< typename T> 
struct some_type_trait:boost :: false_type {};

模板<>
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位即可看到类似内容。在常见的32位平台上考虑 int32_t 。可能是 typedef 设置为 int long ,但一次只能显示两个。 int long 当然是不同的类型。



不难看出,没有解决方法会使32位系统上的 int == int32_t == long 变长。出于同样的原因,在64位系统上,无法使 long == int64_t == long long



如果可以的话,对于 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);


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.

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:

int:           0
int64_t:       1
long int:      0
long long int: 1

However, the program resulting from a 64-bit GCC compile will output:

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:

# 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).

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?


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.

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.


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.

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.

Another example is using a qualifier like same_type (which is pretty common to use in C++0x Concepts):

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&).

I would like to stress that I understand why this is happening, but I am looking for a workaround that does not force me to repeat code all over the place.

解决方案

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.

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.

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?!

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:

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 exactly the same as foo(long).

[edit] With C++11, we now have a standard way to write this:

long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);

这篇关于C语言中的long long int vs. long int vs.int64_t的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆