繁体   English   中英

gcc是否将非常量表达式函数的内置函数视为常量表达式

[英]Is gcc considering builtins of non-constant expression functions to be constant expressions

请参阅更新以获得更好的问题示例。 原始代码有各种各样的问题,使图片混乱

这个问题为什么我可以在constexpr函数中调用非constexpr函数? 提出了以下代码

#include <stdio.h>

constexpr int f()
{
    return printf("a side effect!\n");
}

int main()
{
    char a[f()];
    printf("%zd\n", sizeof a);
}

我回答的是格式不正确gcc 4.8.2允许它( 现场直播 )。

但是,如果我们使用-fno-builtin标志, gcc生成错误( 请参见实时 ):

error: call to non-constexpr function 'int printf(const char*, ...)'
     return printf("a side effect!\n");
                                     ^

所以seems gcc正在考虑将其内置版本的printf作为一个常量表达式。 gcc 文件在这里构建,但没有记录这种情况,其中非constexpr函数的内置可以被认为是常量表达式。

如果确实如此:

  • 是否允许编译器执行此操作?
  • 如果他们被允许,他们不必记录它是否符合要求?
  • 这可以被视为一个扩展,如果是这样的话,似乎这需要一个警告,因为C ++草案标准1.4实施合规性8段说( 强调我的 ):

符合条件的实现可能具有扩展(包括其他库函数),前提是它们不会改变任何格式良好的程序的行为。 需要实现来诊断使用根据本国际标准格式不正确的扩展的程序 但是,这样做之后,他们就可以编译和执行这样的程序。

更新

正如凯西所指出的那样,原始问题中有一些事情会使它成为一个糟糕的例子。 一个简单的例子是使用std :: pow ,它不是constexpr函数:

#include <cmath>
#include <cstdio>

constexpr double f()
{
    return std::pow( 2.0, 2.0 ) ;
}

int main()
{
    constexpr double x = f() ;

    printf( "%f\n", x ) ;
}

编译和构建时没有任何警告或错误( 请参见实时 ),但添加-fno-builtin会使其生成错误( 请参见实时 )。 注意: 为什么数学函数不是c ++ 11中的constexpr

error: call to non-constexpr function 'double pow(double, double)'
     return std::pow( 2.0, 2.0 ) ;
                               ^

是的, gcc正在考虑将一些内置函数作为constexpr,即使标准没有明确标记它们。 我们可以在gcc错误报告[C ++ 0x] sinh vs asinh vs constexpr中找到与cmath中的数学函数有关的讨论,其中说:

LWG 2013似乎确实允许GCC将这些功能视为constexpr。 所以,固定为4.7

这是指2013年LWG问题,其最初提议的决议是将以下内容添加到第17.6.5.6[constexpr.functions]强调我的未来 ):

[...]此外,如果该函数的定义满足必要的约束,则实现可以声明任何函数为constexpr [...]

但是在C ++ 11之后,分辨率被颠倒了,最终的分辨率结束为:

[...]实现不得将任何标准库函数签名声明为constexpr,除非明确要求它。[...]

所以这是( 在C ++ 14中一个显式不符合的扩展 ,据我所知,这在C ++ 11中是不符合的,因为它改变了可观察的行为,因此不允许通过as-if规则

Jonathan Wakely指出了一个libstdc++邮件列表讨论: PR libstdc ++ / 49813重新访问:constexpr on functions(和builtins) ,由于上面列出的问题,讨论了重新打开上面提到的错误报告:

我相信我们应该根据LWG 2013的实际解决方案重新打开这个bug(禁止添加constexpr)。

FE不应该在严格一致性模式下将builtins视为constexpr。

我们应该完全从<cmath>中删除_GLIBCXX_CONSTEXPR,或者使其成为__STRICT_ANSI__的条件。

GCC 考虑f()是一个常量表达式。 查看您链接的第一个示例程序的诊断信息:

main.cpp: In function 'int main()':
main.cpp:10:19: warning: ISO C++ forbids variable length array 'a' [-Wvla]
         char a[f()];
                   ^

编译器不认为f()是一个常量表达式,程序实际上是使用GCC的扩展,它允许可变长度数组 - 具有非常量大小的数组。

如果更改程序以强制f()为常量表达式:

int main() {
    constexpr int size = f();
    char a[size];
    printf("%zd\n", sizeof a);
}

GCC报告错误

main.cpp: In function 'int main()':
main.cpp:10:32:   in constexpr expansion of 'f()'
main.cpp:5:41: error: 'printf(((const char*)"a side effect!\012"))' is not a constant expression
         return printf("a side effect!\n");
                                         ^

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM