【问题标题】:Why is the format in printf marked as restrict?为什么 printf 中的格式标记为限制?
【发布时间】:2018-11-23 07:26:41
【问题描述】:

我刚好看到printf(和其他fprintf类函数)的原型——

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

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

从 C 标准中引用相同内容的示例是 here

我认为将格式标记为restrict 的一个好处是可以避免函数在执行过程中被修改格式字符串(比如说因为%n 格式说明符)。

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

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

因为这里显然有一个别名。为什么restrict 关键字被添加到printfformat 参数中?

【问题讨论】:

标签: c printf restrict


【解决方案1】:

cppreference

在每次执行声明了受限指针P 的块期间(通常每次执行以P 为函数参数的函数体),如果某个对象可通过@987654325 访问@(直接或间接)以任何方式修改然后对该对象的所有访问(读取和写入)必须在该块中通过P(直接或间接)发生,否则行为未定义。

(强调我的)

意思是:

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

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

restrict 唯一未定义的是“在printf 运行时使用%…n 写入格式字符串”(例如char f[] = "%hhn"; printf(f, (signed char *)f);)。

为什么restrict 关键字被添加到printf 的格式参数中?

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

由于restrict 可能会或可能不会使代码运行得更快,但它永远不会让它变慢(假设编译器是理智的),所以应该始终使用它,除非:

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

【讨论】:

  • 当我在发布问题之前阅读时,我确信restrict 仅在有写入时才重要,但this 示例让我感到困惑。它显然只是说访问不会发生冲突。没有说任何关于写入的事情。
  • @AjayBrahmakshatriya 也许措辞有点草率?示例中的指针必须指向不同的事物,因为其中一个被写入。
  • 是的,措辞对我来说并不完全清楚。我同意,如果两者都没有写,那应该没关系。我担心的是,如果标准规定它们也不应该为读取使用别名,编译器是否可以基于此做出一些别名假设。
  • @HolyBlackCat 所以我最后的看法是,如果没有对对象进行修改,则允许这两个指针使用别名。如果这是正确的,我完全理解为什么printfrestrict,当然是为了优化。我最初的困惑源于我的(错误的)假设,即即使两者都只是阅读,也不允许它们使用别名。仅当这可以得到标准中的某些声明的支持时。但我现在认为 cpp 参考的话是正确的。谢谢1
  • @HolyBlackCat 我觉得现在好多了。据我了解,restrict 的原因是:“用于接收%..n 说明符结果的指针不允许与指向格式字符串的指针相同”。有点道理。我将删除 DV 并清理 cmets。谢谢。
【解决方案2】:

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

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

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

这允许printf() 包含不关心因此类副作用而改变格式字符串的代码。

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


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

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

@HolyBlackCat 有一个很好的 "%n" 示例。

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

【讨论】:

  • 另外,我很清楚它如何保护函数免受修改格式的副作用。我在问题中也提到了这一点。我的问题是,如果指针只是要读取,非别名约束是否也适用?如果是,是否会使我在问题中提到的示例无效?
  • 哦,stdout 这里是FILE* 对象。明白了。
  • char format[] = "%s"; printf(format, format); 没问题。
  • @AjayBrahmakshatriya 我的回答重点是回答标题问题“为什么 printf 中的格式标记为限制?”
  • 是的,我现在更了解restrict 以及为什么它对printf 很重要。谢谢!
猜你喜欢
  • 2023-03-17
  • 2012-04-17
  • 1970-01-01
  • 2017-02-27
  • 2020-11-10
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
相关资源
最近更新 更多