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全局的访问都是通过唯一的指针参数进行s的strlen。其中一些 ( str = ...) 甚至不涉及任何指针。如果我的理解是正确的,这就不符合strlen独立性,因此不符合顺序。
总而言之,我的解释是否正确,并且strlen不能无序?这也许只是一个措辞问题,但它的目的是无序的?
该提案[[unsequenced]]声称与 GCC 不同[[gnu::const]],支持指针参数。然而,我不确定措辞是否反映了这一点,以及反映到什么程度。
我的问题是像这样的函数
strlen是否可以独立。
首先,规范相关部分的措辞很糟糕。例如,在某些地方语法与表面意图不匹配,在其他地方语法不正确,从而使预期含义难以解析,并且有点多余。这个重写更好地传达了我认为规范的意思:
如果满足以下条件,则通过函数调用X观察对象:
X生命周期在调用之前开始,并且X和呼叫同步,并且X在呼叫期间对 的访问进行排序。在这种情况下,如果在X调用之前发生任何存储,则最后一个此类存储写入的值被认为是X调用观察到的值。否则, 的初始值X是调用观察到的值。
如果对于调用C to观察到的每个对象,函数指针值f是独立的,X*f
如果这样的C观察到的任何访问X是通过基于 的指针参数的左值*f,则存在一个唯一的指针参数P,使得这样的C*f进行的每次访问都应通过基于 的左值;XP
否则,在同一程序执行期间观察 的值的每个此类CX都会观察到相同的值。
如果派生函数指针值是独立的,则函数定义是独立的。
使用函数指针作为定义的主要主题是从原文中得出的。我认为它是为了澄清独立性是指由其地址标识的函数,而不是通过名称或实现来标识。因此,程序可能包含两个具有相同名称和相同代码的静态函数,其中一个独立,另一个不独立。
值得注意的是,函数或函数指针是独立的(如果编译器能够识别),这意味着函数调用相对于其他操作可能会重新排序,这就是存在的意义unsequenced。但独立性仅与函数的读取有关,因此它本身不足以启用调用的重新排序。
考虑这个最小的实现:
Run Code Online (Sandbox Code Playgroud)size_t strlen(const char* s) { size_t len = 0; for (; *s; ++s) { ++len; } return len; }首先,是否
*s认为是基于参数的访问?
简短的回答:是的。
长答案: 这*s是一个左值。它出现在将执行左值转换的上下文中。该左值转换执行对引用对象的读取,这是对该对象的访问。我认为没有任何*s不基于 的解释的空间s,它是函数的参数。
然而,(6.6) 可能是一个问题。请注意,(6.5) 表示“在对 f 的所有调用中对 X 的所有访问”,而 (6.6) 表示“对 X 的所有访问”,后者范围更广,也可能适用于函数外部的访问。
有点。该规定与指针值无关,而是与将指针提供给函数的函数参数有关。因此,将其解释为在调用上下文之外应用意味着在不取消独立资格f的情况下根本无法访问所讨论的对象。我相信这不是本意,而且我上面对条款的重写对此更加清楚。ff
总之,我的解释是否正确,并且 strlen 不能无序?这也许只是一个措辞问题,但它的目的是无序的?
如果您的解释是正确的,那么基本上没有函数会被取消排序(因为函数必须是独立的才能被取消排序)。
当我解释规范时,strlen()提供的定义定义了一个未排序的函数。我注意到这与它是否实际带有注释无关[[unsequenced]]。