【发布时间】:2022-01-21 10:29:57
【问题描述】:
众所周知,实际参数的计算顺序因一个 C 编译器而异。但正如 ISO 9899:1999 在 §6.5.2.2.10 中所述:
未指定函数指示符、实际参数和实际参数中的子表达式的计算顺序,但在实际调用之前有一个顺序点。
自从我在 80 年代开始使用 C 语言以来,我从来没有遇到过这样的编译器,它生成的代码是在实际参数之后评估函数指示符或与实际参数交错。因此在应用程序中使用以下(简化的)代码是否“安全”:
void* self;
(self = getPointerToObject())->classPtr->methodX(self);
或者真的有必要这样做:
void* self;
int (*methodPtr)(void*);
(methodPtr = (self = getPointerToObject())->classPtr->methodX, methodPtr(self));
在函数指示符和参数评估之间获得一个明确的序列点(以一定的性能为代价)?
是否有 C 编译器会在第一个代码被剪断时生成代码不起作用(即,将未定义的 self 参数提供给 methodX)?
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
-
@Machavity 我必须做什么才能看到整个讨论?移动后,部分讨论似乎丢失了。
-
一些 cmets 因不具建设性而被移除。如果您觉得有问题,请在帖子中提出版主标记。
-
关于“我从来没有遇到过这样的编译器……”:你怎么知道的?假设你有编译器 X,并且你用它编译了程序 P0、P1、P2、... Pn,并且在这些程序中,X 都没有生成在相关函数指示符之前评估函数参数的代码。这不会让您知道 X 不会这样做,因为 X 可能会为某些未经测试的程序 P973 这样做......
-
... 例如,也许对于一些足够复杂的函数指示符表达式,其中存在与参数基本相同或重叠的子表达式,优化将在完成其余复杂函数指示符表达式之前完成参数评估.您无法知道仅通过测试不会发生这种情况,因此需要编译器文档或检查源代码或其他文档。是你做的吗?如果不是,你怎么知道?
标签: c sequence-points