【问题标题】:Where stored array, if I declared it after return?如果我在返回后声明它,存储数组在哪里?
【发布时间】:2013-09-05 12:10:00
【问题描述】:

我有代码 C++11:

template<std::size_t n>
static inline constexpr uint32_t mask() noexcept 
{ 
    static_assert(n <= 32, "!");
    using list = uint32_t[]; 

    return list{
        0x0u, 
        0x1u,       0x3u,       0x7,        0xfu,       0x1fu,       0x3fu,       0x7fu,       0xffu, 
        0x1ffu,     0x3ffu,     0x7ffu,     0xfffu,     0x1fffu,     0x3fffu,     0x7fffu,     0xffffu, 
        0x1ffffu,   0x3ffffu,   0x7ffffu,   0xfffffu,   0x1fffffu,   0x3fffffu,   0x7fffffu,   0xffffffu, 
        0x1ffffffu, 0x3ffffffu, 0x7ffffffu, 0xfffffffu, 0x1fffffffu, 0x3fffffffu, 0x7fffffffu, 0xffffffffu
    } [ n ]; 
}

问:list 数组存储在哪里? (在静态内存、自动内存或无存储位置)?

【问题讨论】:

  • 这是一个你应该问你的编译器的问题,而不是我们。但是,为什么要存储它?
  • 它可能会被完全优化,并且值会被内联。

标签: c++ arrays memory c++11


【解决方案1】:

在正常功能中,它将是临时的,存储在自动内存中。由于n 是编译时常量,因此可以对其进行优化以简单地返回值,移除数组。

但是,这是constexpr,因此应该在编译时计算返回值。该数组在运行时根本不应该存在。

【讨论】:

    【解决方案2】:

    由于函数中的n 不能是变量,例如

    size_t n;
    std::cin >> n;
    
    std::cout << mask<n>() << std::endl;
    

    将无法编译,因为n 在编译时不是常量,编译器根本不需要存储数组。通常,constexpr 函数不应生成任何“代码”,而不是某种常量值。

    我的编译器似乎不接受此处发布的代码 - 可能是因为它现在有点古老(它是 gcc 4.6.3 - 我也尝试过 clang++,但它失败了,因为它尝试使用 4.6.3 头文件,它显然不是“铿锵味”)。

    当然,这样写要容易得多:

    template<std::size_t n>
    inline constexpr uint32_t mask() noexcept 
    { 
        static_assert(n <= 32, "!");
    
        return (1u << n) -1;
    }
    

    为了应对 n == 32 的特殊情况(并避免 UB,尽管在大多数架构中,上面可能会做正确的事情):

    template<>
    inline constexpr uint32_t mask<32>() noexcept 
    { 
        return ~0;
    }
    

    【讨论】:

    • 如果 n == 32,您的掩码会导致未定义的行为。
    • @MikeSeymour & @Kurshid:谢谢,我添加了u 以确保。即使您必须添加一个额外的if (n == 32) return 0xffffffff;,我会说这比一长串值更好的解决方案。
    • @Mike:这不是很好定义的。溢出(将非零高位从左边推开)会是,但是移动大于或等于宽度的值仍然是未定义的,即使对于无符号类型也是如此。
    • @BenVoigt:你是对的。二十年后,我应该知道我将永远了解 C++ 中基本算术的工作原理。
    • 很好的修复。请注意,占您部署目标的许多的实际架构会将1u &lt;&lt; 32 视为与1u &lt;&lt; 0 相同,因为它们隐式屏蔽移位操作数并且仅使用低5 位。这就是为什么即使对于无符号类型也将其指定为未定义行为的原因。
    猜你喜欢
    • 2019-05-28
    • 1970-01-01
    • 2018-11-09
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    相关资源
    最近更新 更多