strlen 可以是[[未排序]]吗?

Jan*_*tke 3 c language-lawyer c23

我不清楚C23 工作草案中关于未排序函数的措辞。除其他属性外,未排序的函数必须是独立的

(6)通过函数调用观察对象X

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

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

函数指针值f独立的,如果

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

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

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

我的问题是像这样的函数strlen是否可以独立。考虑这个最小的实现:

size_t strlen(const char* s) {
    size_t len = 0;
    for (; *s; ++s) { ++len; }
    return len;
}
Run Code Online (Sandbox Code Playgroud)

首先,是否*s认为是基于参数的访问?我相信访问基于参数,即指针参数,因此只有(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
Run Code Online (Sandbox Code Playgroud)

并非所有对str全局的访问都是通过唯一的指针参数进行sstrlen。其中一些 ( str = ...) 甚至不涉及任何指针。如果我的理解是正确的,这就不符合strlen独立性因此不符合顺序

总而言之,我的解释是否正确,并且strlen不能无序这也许只是一个措辞问题,但它的目的是无序的


注意可能的意图

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

参见N2956 5.8 与 GCC const 和 pure 的一些区别

Joh*_*ger 5

我的问题是像这样的函数strlen是否可以独立。

首先,规范相关部分的措辞很糟糕。例如,在某些地方语法与表面意图不匹配,在其他地方语法不正确,从而使预期含义难以解析,并且有点多余。这个重写更好地传达了我认为规范的意思:


如果满足以下条件,则通过函数调用X观察对象:

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

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

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

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

  • 否则,在同一程序执行期间观察 的值的每个此类CX都会观察到相同的值。

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


使用函数指针作为定义的主要主题是从原文中得出的。我认为它是为了澄清独立性是指由其地址标识的函数,而不是通过名称或实现来标识。因此,程序可能包含两个具有相同名称和相同代码的静态函数,其中一个独立,另一个不独立。

值得注意的是,函数或函数指针是独立的(如果编译器能够识别),这意味着函数调用相对于其他操作可能会重新排序,这就是存在的意义unsequenced。但独立性仅与函数的读取有关,因此它本身不足以启用调用的重新排序。

考虑这个最小的实现:

size_t strlen(const char* s) {
    size_t len = 0;
    for (; *s; ++s) { ++len; }
    return len;
}
Run Code Online (Sandbox Code Playgroud)

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

简短的回答:是的。

长答案: 这*s是一个左值。它出现在将执行左值转换的上下文中。该左值转换执行对引用对象的读取,这是对该对象的访问。我认为没有任何*s不基于 的解释的空间s,它是函数的参数。

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

有点。该规定与指针值无关,而是与将指针提供给函数的函数参数有关。因此,将其解释为在调用上下文之外应用意味着在不取消独立资格f的情况下根本无法访问所讨论的对象。我相信这不是本意,而且我上面对条款的重写对此更加清楚。ff

总之,我的解释是否正确,并且 strlen 不能无序?这也许只是一个措辞问题,但它的目的是无序的?

如果您的解释是正确的,那么基本上没有函数会被取消排序(因为函数必须是独立的才能被取消排序)。

当我解释规范时,strlen()提供的定义定义了一个未排序的函数。我注意到这与它是否实际带有注释无关[[unsequenced]]