构建一个'长期'

时间:2012-05-10 04:18:28

标签: gcc

如何在gcc中构建long long,类似于通过int构建int()

以下在gcc中失败(4.6.3 20120306)(但以MSVC为例)。

myFunctionCall(someValue, long long());

错误expected primary-expression before 'long'(列位置表示第一个长点是位置)。

一个简单的改变

myFunctionCall(someValue, (long long)int());

工作正常 - 即构建int并投射到long long - 表示gcc不喜欢long long ctor。

摘要解决方案

总结下面@birryree的精彩解释:

  • 许多编译器不支持long long(),可能不符合标准
  • 构建long long相当于文字0LL,因此请使用myFunctionCall(someValue, 0LL)
  • 或者使用typedef long_long_t long long然后使用long_long_t()
  • 最后,考虑使用uint64_t ,如果您在任何平台上的64位类型之后,而不是 64的类型比特,但可能在不同的平台上有所不同。

1 个答案:

答案 0 :(得分:5)

我希望得到关于预期行为的确切答案,所以我posted a question on comp.lang.c++.moderated并得到了一些很好的答案。 所以感谢Johannes Schaub, Alf P. Steinbach(均来自SO)和Francis Glassborrow获取一些信息

这不是GCC中的错误 - 实际上它会突破多个编译器 - GCC 4.6,GCC 4.7和Clang如果尝试这种语法就会抱怨像primary expression expected before '('这样的类似错误:

long long x = long long();

某些基元有空格,如果由于绑定需要使用构造函数样式初始化,则不允许这样做(long()已绑定,但long long()有空闲long) 。其中包含空格的类型(如long long)不能使用type() - 构造形式。

MSVC在这里更宽松,虽然技术上非标准兼容(并且它不是你可以禁用的语言扩展)。

解决方案/变通方法

您可以选择其他选项:

  • 使用0LL代替尝试long long()作为您的值 - 它们会产生相同的值。

    这也是大多数代码的编写方式,因此对于阅读代码的其他人来说,这是最容易理解的。

  • 根据您的评论,您似乎真的想要long long,因此您可以typedef自己始终保证您拥有long long类型,如下所示:

    int main() {
        typedef long long MyLongLong;
        long long x = MyLongLong(); // or MyLongLong x = MyLongLong();
    }
    
  • 使用模板来解决需要明确命名的问题:

    template<typename TypeT>
    struct Type { typedef TypeT T(); };
    
    // call it like this:
    long long ll = Type<long long>::T();
    
  • 正如我在评论中提到的,您可以使用别名类型,例如int64_t(来自<cstdint>),跨越常见平台的是typedef long long int64_t。这比此列表中的先前项目更依赖于平台。

    int64_t是一个64位的固定宽度类型,通常在linux-x86和windows-x86等平台上有多宽long longlong long至少为64位宽,但可以更长。如果您的代码只能在某些平台上运行,或者您确实需要固定宽度类型,那么这可能是一个可行的选择。

C ++ 11解决方案

感谢C ++新闻组,我学会了一些其他方法来做你想做的事情,但不幸的是它们只是在C ++ 11领域(并且MSVC10也不支持,只有非常新的编译器)无论哪种方式):

  • {}方式:

    long long ll{}; // does the zero initialization
    
  • 使用Johannes所指的C ++ 11中的'bord工具'std::common_type<T>

    #include <type_traits>
    
    int main() {
        long long ll = std::common_type<long long>::type();
    }
    

对于POD类型,()0初始化之间是否存在真正的差异?

你在评论中这样说:

  

我不认为默认ctor总是返回零 - 更典型的行为是保持内存不变。

嗯,对于原始类型,这根本不是真的。

来自 ISO C ++ Standard / 2003 第8.5节(没有2011,抱歉,但此信息没有太大变化):

  

默认初始化T类型的对象意味着:

     

- 如果T是非POD类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认值,则初始化是错误的   构造函数);

     

- 如果T是数组类型,则每个元素都是   缺省初始化;

     

- 否则,该对象为零初始化。

最后一个句子在这里最重要,因为long longunsigned longintfloat等都是标量/ POD类型,因此调用这样的事情:

int x = int();

完全相同:

int x = 0;

生成的代码示例

以下是代码中实际发生的更具体的示例:

#include <iostream>

template<typename T>
void create_and_print() {
   T y = T();
   std::cout << y << std::endl;
}

int main() {
   create_and_print<unsigned long long>();

   typedef long long mll;
   long long y = mll();
   long long z = 0LL;

   int mi = int();
}

用以下内容编译:

g++ -fdump-tree-original construction.cxx

我在生成的树转储中得到了这个:

;; Function int main() (null)
;; enabled by -tree-original

{
  typedef mll mll;
  long long int y = 0;
  long long int z = 0;
  int mi = 0;

  <<cleanup_point <<< Unknown tree: expr_stmt
  create_and_print<long long unsigned int> () >>>>>;
  <<cleanup_point   long long int y = 0;>>;
  <<cleanup_point   long long int z = 0;>>;
  <<cleanup_point   int mi = 0;>>;
}
return <retval> = 0;



;; Function void create_and_print() [with T = long long unsigned int] (null)
;; enabled by -tree-original

{
  long long unsigned int y = 0;

  <<cleanup_point   long long unsigned int y = 0;>>;
  <<cleanup_point <<< Unknown tree: expr_stmt
  (void) std::basic_ostream<char>::operator<< ((struct __ostream_type *) std::basic_ostream<char>::operator<< (&cout, y), endl) >>>>>;
}

生成的代码含义

因此,从上面生成的代码树中,注意我的所有变量都只是用0初始化,即使我使用构造函数式的默认初始化,就像使用int mi = int()一样。 GCC将生成恰好int mi = 0的代码。

我的模板函数只是尝试对typename T传递的某些内容进行默认构建,其中T = unsigned long long也只生成0 - 初始化代码。


结论

总之,如果你想默认构造原始类型/ POD,就像使用0一样。