C标准是否要求平台不得定义超出标准规定的行为

sup*_*cat 7 c undefined-behavior language-lawyer

C标准清楚地表明允许编译器/库组合使用以下代码执行任何操作:

int doubleFree(char *p)
{
  int temp = *p;
  free(p);
  free(p);
  return temp;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果编译器不需要使用特定的捆绑库,那么C标准中是否有任何禁止库定义有意义行为的内容?举一个简单的例子,假设代码是为具有引用计数指针的平台编写的,这样p = malloc(1234); __addref(p); __addref(p);在前两次调用之后free(p)会减少计数器但不释放内存.编写用于此类库的任何代码自然只能用于这样的库(并且__addref()调用可能在大多数其他库中失败),但是在许多情况下,例如需要重复传递字符串时,这样的功能可能会有所帮助.期望获得一个字符串的方法,strdup并因此调用free它.

如果库为某些操作定义了一个有用的行为,比如双重释放指针,那么C标准中是否有任何内容可以授权编译器单方面破坏它?

Sha*_*our 3

这里确实有两个问题,您正式提出的一个问题和您在对其他人提出的问题的评论中概述的更广泛的问题。

您的正式问题是通过未定义行为的定义和4一致性部分来回答的。定义说(强调我的):

使用不可移植或错误的程序构造或错误数据时的行为,本国际标准对此没有强加要求

强调非便携性并且没有强加任何要求。这确实说明了一切,编译器可以自由地以不愉快的方式进行优化,或者也可以选择将行为记录下来并明确定义,这当然意味着程序不再严格符合要求,这将我们带到以下部分4

严格遵守的程序应仅使用本国际标准中指定的语言和库的功能。2)它不应产生依赖于任何未指定、未定义或实现定义的行为的输出,并且不应超过任何最低实现限制。

但只要不破坏一致的程序,一致的实现就允许扩展:

一致的实现可以有扩展(包括附加的库函数),只要它们不改变任何严格一致的程序的行为。3)

正如C 常见问题解答所述

现实的、有用的、严格遵守的程序很少。另一方面,仅仅符合要求的程序可以使用它想要的任何特定于编译器的扩展。

您的非正式问题涉及编译器对未定义行为采取更积极的优化机会,从长远来看,担心这将使现实世界的系统编程变得不可能。虽然我确实理解这种相对较新的激进立场对许多程序员来说似乎非常不友好,但如果人们不能用它构建有用的程序,编译器最终不会持续很长时间。John Regehr 的相关博客文章:Proposal for aFriendly Dialect of C

有人可能会提出相反的观点,即编译器已经付出了很大的努力来构建扩展来支持标准不支持的各种需求。我认为GCC hacks in the Linux kernel这篇文章很好地证明了这一点。它涉及 Linux 内核所依赖的许多 gcc 扩展,并且clang通常尝试支持尽可能多的gcc扩展。

我不清楚编译器是否删除了对未定义行为的有用处理,这些行为阻碍了有效的系统编程。我认为关于系统编程中已利用且不再有效的未定义行为的个别案例的替代方案的具体问题对于社区来说是有用且有趣的。