当前位置: 首页 > 知识库问答 >
问题:

__func__指针的两个constexpr实例的差还是constexpr吗?

东郭勇
2023-03-14

这是有效的 C 吗?

int main() {
    constexpr auto sz = __func__ - __func__;
    return sz;
}

GCC和MSVC认为没问题,Clang认为不是:编译器资源管理器。

所有编译器都同意这个是可以的:编译器资源管理器。

int main() {
    constexpr auto p = __func__;
    constexpr auto p2 = p;
    constexpr auto sz = p2 - p;
    return sz;
}

Clang再次不喜欢这个,但其他人都同意:编译器资源管理器

int main() {
    constexpr auto p = __func__;
    constexpr auto p2 = __func__;
    constexpr auto sz = p2 - p;
    return sz;
}

这上面是什么?我认为不相关的指针上的算术是未定义的行为,但是< code>__func__返回相同的指针,不是吗?我不确定,所以我想我可以测试一下。如果我没记错的话,< code>std::equal_to可以比较不相关的指针,而不会出现未定义的行为:

#include <functional>

int main() {
    constexpr std::equal_to<const char*> eq{};
    static_assert(eq(__func__, __func__));
}

Clang认为eq(__func__,__func__)不是一个常量表达式,即使std::equal_to::运算符()是constexr。其他编译器没有抱怨:编译器资源管理器

克兰也不会编译这个。抱怨__func___==__func__不是常量表达式:编译器资源管理器

int main() {
    static_assert(__func__ == __func__);
}

共有1个答案

邢洋
2023-03-14

C中的__func___是一个标识符。特别是,它引用了一个特定的对象。来自[dcl.fct.def.general]/8:

函数局部预定义变量__func__被定义为表单的定义

static const char __func__[] = "function-name";

其中function-name是实现定义的字符串。这种变量的地址是否不同于程序中任何其他对象的地址,这一点并不明确。

作为函数局部预定义变量,此定义(好像)出现在功能块的开头。因此,该块中__func__的任何使用都将引用该变量。

至于“任何其他对象”部分,变量定义一个对象。< code>__func__命名由该变量定义的对象。因此,在一个函数中,< code>__func__的所有用法都使用同一个变量。未定义的是该变量是否是与其他对象不同的对象。

也就是说,如果您在一个名为foo的函数中,并且在问题的其他地方使用了文字“foo”,那么不禁止实现将变量__func___也作为文字“foo“返回的同一对象。也就是说,标准不要求出现__func___的每个函数都必须存储与字符串文本本身分离的数据。

现在,C的“好像”规则允许实现偏离这一点,但是它们不能以可检测的方式做到这一点。因此,尽管变量本身可能有也可能没有与其他对象不同的地址,但在同一个函数中使用__func__必须表现得好像它们引用的是同一个对象。

Clang似乎没有以这种方式实现__func___。它似乎像返回函数名称的prvalue字符串文本一样实现它。两个不同的字符串文本不必引用同一个对象,因此减去指向它们的指针就是UB。常量表达式上下文中未定义的行为格式不正确。

唯一让我犹豫要不要说Clang在这里是100%错误的是[temp.arg.nontype]/2:

对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或对于指针类型,不应为的地址):

...

  • 一个预定义的__func__变量。

看到了吗,这似乎允许实现过程中出现一些问题。也就是说,虽然__func___在技术上可以是常量表达式,但不能在模板参数中使用它。它被视为字符串文字,即使它在技术上是一个变量。

所以在某种程度上,我可以说标准是两面说话。

 类似资料:
  • GCC 8.2.1和MSVC 19.20编译以下代码,但Clang 8.0.0和ICC 19.0.1无法这样做。 Clang 8.0.0 的错误消息如下: 我注意到它在两种情况下可以用Clang编译: 从最后一个定义中删除括性 将线 替换为

  • 什么时候只能使用其中的一个? 何时可以同时使用和如何选择一个?

  • constexpr-8cc: Compile-time C Compiler constexpr-8cc is a compile-time C compiler implemented as C++14 constant expressions.This enables you to compile while you compile!This project is a port of 8cc

  • 我刚刚偶然发现了GCC和Clang之间关于显式默认constexpr ctor和一些继承的以下差异。。。 GCC立即拒绝代码,而Clang允许实例化这两种类型的非constexpr版本。我的猜测是,叮当声可能是正确的,但我不是百分之百肯定。。。

  • 看看这段代码: < code>Foo有一个成员< code > Foo::bar::nonConstexpr ,它有一个非Constexpr构造函数。所以,我的期望是,这不应该编译。但是它用gcc,clang和msvc编译。这是编译器的bug,还是某个规则允许这段代码编译? 如果我直接将 成员添加到 中,代码将不再编译。 (我遇到了这个问题,因为我期望对全局对象进行静态初始化,但它得到了动态初始化

  • 我试图创建一个在编译时构造然后可以使用的类,当然不需要任何修改它的方法。我对和这两个关键字是新手,所以我可能没有正确使用它们。 下面是我的代码: 一旦被修复,就可以在编译时评估所有所需的计算,因此可以肯定地说,就可以执行我正在尝试的操作。方法只读取data_member而不修改它。 当我编译时,我得到: 引用到构造函数。我看到这是一个问题,但在我的情况下,我将不再修改对象。我怎么告诉编译器呢?