我不清楚C23关于unsequenced项职能的工作草案的措辞.在其他属性中,unsequenced个函数必须为independent:

(6)对象X通过函数调用为observed

  • (6.1)如果两者同步,
  • (6.2)如果X对于呼叫不是本地的,
  • (6.3)如果X具有在函数调用之前开始的生存期,以及
  • (6.4)如果在呼叫期间对X的访问进行了排序;

调用前存储的最后一个值X(如果有的话)被称为调用观察到的值X.

函数指针值findependent,如果

  • (6.5)对于通过不基于该调用的参数的左值对f的某个调用观察到的任何对象X,则在同一程序执行期间对f的所有调用中对X的所有访问都遵循相同的值;
  • (6.6)否则,如果访问基于指针参数,则应存在唯一的此类指针参数P,使得对X的任何访问都应访问基于P的左值.

如果派生的函数指针值是独立的,则函数定义是独立的.

-N3096 $6.7.12.7 p6,为提高可读性而重新格式化

我的问题是,像strlen这样的函数是否可以是independent.请考虑以下最小实施:

size_t strlen(const char* s) {
    size_t len = 0;
    for (; *s; ++s) { ++len; }
    return len;
}

首先,*s是否被认为是基于参数的访问?我认为Access is是基于一个参数,即一个指针参数,所以只有(6.6)的限制是相关的.

然而,(6.6)可能是一个问题.请注意,(6.5)表示"在对f的所有调用中,所有访问都是X",而(6.6)表示"所有访问都是X",范围更广,也可能适用于函数外部的访问.那么,以下情况就是一个问题:

struct string {
    char data[N];
} str;
// ...
strlen(str.data); // A
str = ...;
strlen(str.data); // B

并不是所有对str的全局访问都通过唯一的指针参数sstrlen进行.其中一些(str = ...)甚至不涉及任何指针.如果我的理解是正确的,那么strlen就没有资格成为independent,因此unsequenced也就没有资格了.

这可能只是一个措辞问题,但它的目的是成为一架unsequenced


关于可能的意图的说明

[[unsequenced]]的建议声称,与GCC的[[gnu::const]]不同,支持指针参数.然而,我不确定措辞是否反映了这一点,以及反映到了什么程度.

N2956 5.8 Some differences with GCC const and pure

推荐答案

我的问题是,像strlen这样的功能是否可以独立.

作为一个初步问题,该规范相关部分的措辞很糟糕.例如,在某些地方,语法与表面上的意图不匹配,而在其他地方,语法不正确,以使意图难以解析的方式,并且有点多余.这次重写更好地传达了我认为规范的意思:


对象X通过函数调用是observed,如果

  • X的生命周期从调用之前开始,并且
  • X和呼叫同步,并且
  • 在呼叫期间对X的访问进行排序.

在这种情况下,如果在调用之前发生了对X的任何存储,则最后一个这样的存储写入的值被认为是调用观察到的值X.否则,调用观察到的初始值为X.

函数指针值findependent,如果对于由调用C*f观察到的每个对象X

  • 如果这样的C观察X的任何访问是通过基于指针参数*f的左值进行的,则存在*f的唯一指针参数P,使得这样的CX的每次访问都将经由基于P的左值;

    否则

  • 在观察值X的相同程序执行期间,每个这样的C都观察到相同的值.

函数定义是独立的,如果派生函数 指针值是独立的.


使用函数指针作为定义的主要主题取自原始文本.我认为这是为了澄清这一点,即独立性是关于由其地址确定的功能,而不是通过名称或实现.因此,一个程序可能包含两个具有相同名称和相同代码的静态函数,其中一个独立,另一个不独立.

值得注意的是,函数或函数指针是独立的--如果编译器识别的话--说明函数调用相对于其他操作可能会重新排序,这就是unsequenced的意义所在.但是独立性只与函数的读取有关,因此它本身不足以启用调用的重新排序.

请考虑以下最小实施:

size_t strlen(const char* s) {
    size_t len = 0;
    for (; *s; ++s) { ++len; }
    return len;
}

首先,*s是否被认为是基于参数的访问?

简短的回答是:是的.

长久以来的答案是:*s是一个左值.它出现在将执行左值转换的上下文中.该左值转换执行对被引用对象的读取,这是对该对象的访问.我看不到*s不是基于s的任何解释的余地,s是函数的一个参数.

然而,(6.6)可能是一个问题.请注意,(6.5)表示"在所有对f的调用中对X的所有访问",而(6.6)表示"对X的所有访问",后者范围更广,也可能适用于函数外部的访问.

说大也大吧.该规定不是关于指针值,而是关于通过其将指针提供给函数的函数参数.因此,将其解释为在调用f的上下文之外应用将意味着,如果不取消f作为独立对象的资格,则在f之外根本无法访问所述对象.我相信,这不是我的意图,我在上面重写的条款对这一点更加明确.

这可能只是一个措辞问题,但它的本意是一个没有顺序的问题?

如果您的解释是正确的,那么基本上no个函数将被取消排序(因为一个函数必须是独立的才能被取消排序).

在我解释该规范时,提供的strlen()个定义定义了一个未排序的函数.我注意到,这与它是否包含[[unsequenced]]注释无关.

C++相关问答推荐

括号中的堆栈实现错误问题

为什么可以通过指向常量int的指针间接地改变整数的值?

这是一个合法的C Strdup函数吗?

如何在C宏中确定 struct 中元素的类型?

可以将C变量限制为特定的读/写速度吗?

X86/x64上的SIGSEGV,由于原始内存访问和C中的DS寄存器之间的冲突,在Linux上用TCC编译为JIT引擎

N的值设置为0或1(未定义的行为),而我正在try 学习realloc和Malloc的用法

是什么让numpy.sum比优化的(自动矢量化的)C循环更快?

实现简单字典时C语言中的段错误

理解C版宏(看起来像未声明的变量?)

在Linux上使用vscode和lldb调试用Makefile编译的c代码

等同于铁 rust 的纯C语言S未实现!()宏

如何在C中使数组变量的值为常量?

在txt文件中找到指定的字符串,并从数字中减go 相同的值

如何在POSIX-UEFI中获得输入?

在C中访问数组中的特定值

在C中包装两个数组?

致命错误:ASM/rwan ce.h:没有这样的文件或目录.符号链接还不够

链接器脚本和C程序使用相同的头文件,这可能吗?

将size_t分配给off_t会产生符号转换错误