5

gcc中如何构造a long long,类似于构造intviaint()

以下在 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 longctor。

总结解决方案

总结以下来自@birryree 的精彩解释:

  • 许多编译器不支持long long()并且可能不符合标准
  • 构造long long等价于文字0LL,所以使用myFunctionCall(someValue, 0LL)
  • 或者使用typedef long_long_t long longthenlong_long_t()
  • 最后,uint64_t 如果您在任何平台上追求一种正好是 64 位的类型,而不是至少64 位但可能在不同平台上有所不同的类型,请考虑使用。
4

1 回答 1

5

我想要一个关于预期行为的明确答案,所以我发布了一个问题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()-construction 形式。

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(from <cstdint>),它在通用平台上是typedef long long int64_t. 这比此列表中的前面的项目更依赖于平台。

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

C++11 解决方案

感谢 C++ 新闻组,我学到了一些额外的方法来做你想做的事,但不幸的是,它们只在 C++11 的领域内(而且 MSVC10 也不支持,而且只有非常新的编译器会):

  • {}方式:

    long long ll{}; // does the zero initialization
    
  • 在 C++11 中使用 Johannes 所说的“边框工具”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 long, unsigned long, int,float等都是标量/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,即使我使用构造函数样式的默认初始化,例如 with int mi = int()。GCC 将生成刚刚执行的代码int mi = 0

我的模板函数只是尝试对一些传入的typename T, where进行默认构造T = unsigned long long,也只生成了一个0-initialization 代码。


结论

所以总而言之,如果你想默认构造原始类型/POD,就像使用0.

于 2012-05-10T15:54:23.453 回答