为什么 printf 中的格式标记为 restrict?

Why is the format in printf marked as restrict?

我只是碰巧看了 printf 的原型(以及其他 fprintf class 函数)-

int printf(const char * restrict format, ...);

如果我理解正确,关键字 restrict 不允许通过两个指针访问同一对象,如果其中一个指针被标记为 restrict

引用 C 标准的相同示例是 here

我认为将格式标记为 restrict 的一个好处是可以避免函数在执行期间可能会修改格式字符串(比如由于 %n 格式说明符)。

但这是否施加了更大的限制?这是否会使以下函数调用无效?

char format[] = "%s";
printf(format, format);

因为这里明显是走样了。为什么要将 restrict 关键字添加到 printfformat 参数中?

cppreference

During each execution of a block in which a restricted pointer P is declared (typically each execution of a function body in which P is a function parameter), if some object that is accessible through P (directly or indirectly) is modified, by any means, then all accesses to that object (both reads and writes) in that block must occur through P (directly or indirectly), otherwise the behavior is undefined.

(强调我的)

意思是:

char format[] = "%s";
printf(format, format);

定义明确,因为 printf 不会尝试修改 format

restrict 唯一未定义的是 'writing to the format string using %…n while printf is running'(例如 char f[] = "%hhn"; printf(f, (signed char *)f);)。

Why was the restrict keyword added to the format argument of printf?

restrict 本质上是编译器可能用来更好地优化代码的提示。

由于 restrict 可能会或可能不会使代码 运行 更快,但它永远不会使其变慢(假设编译器是正常的),因此应该 始终,除非:

  • 使用它会导致 UB
  • 在这种特定情况下,它没有显着提高性能

Why is the format in printf marked as restrict?

int printf(const char * restrict format, ...);

some_type * restrict format中的restrict是调用代码和函数printf()之间的"contract"。它允许 printf() 假定对 format 指向的数据的唯一可能更改发生在函数直接执行的操作上,而不是其他指针的副作用。

这允许 printf() 包含不关心由此类副作用引起的格式字符串更改的代码。

由于format指向const数据,所以printf()也不允许更改数据。然而,这是 restrict 功能的附属功能。


考虑下面的病态代码。它违反了合同,因为 printf() 肯定会改变 *stdout 的状态,而 *stdout 又会改变 .ubuf.

strcpy(stdout->ubuf, "%s");
printf(stdout->ubuf, "Hello World!\n");

有一个很好的例子 "%n"

关键:restrict 要求调用代码不作为 format 传递,任何指向可能因 printf() 操作而改变的字符串的指针。