13

拿这个代码:

int issuecode(int i)
{
  return 2 * i;
}

int main(int argc, char **argv)
{
  return issuecode(argc);
}

我理解它的方式,如果编译为 C 程序,它将具有未定义的行为。我根据这些标准报价进行推理:

C99, 7.26 (或 C11, 7.31)

为方便起见,以下名称分组在各个标题下。无论程序包含什么标头,下面描述的所有外部名称都是保留的。

C99、7.26.2(或 C11、7.31.2)

is以or和小写字母开头的函数名称to可以添加到<ctype.h>标头中的声明中。

C99, 7.1.3 (或 C11, 7.1.3)

  1. 每个标头声明或定义其相关子条款中列出的所有标识符,并可选地声明或定义其相关的未来库方向子条款中列出的标识符和始终保留用于任何用途或用作文件范围标识符的标识符。

    [...]

    • 以下任何子条款(包括未来的库方向)中具有外部链接的所有标识符始终保留用作具有外部链接的标识符。
  2. [...] 如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的除外),或将保留标识符定义为宏名称,则行为未定义。

综上所述,我相信函数名issuecode实际上是为 in 保留使用的<ctype.h>,因此该程序在技术上具有 UB。

问题 0(健全性检查):我对标准的解读是否正确,程序的行为在技术上是否未定义?

问题一:程序编译成C++代码会有UB吗?

我相信答案是“不”,因为从下面的引用中,我会说 C 的“未来库方向”不是 C++ 标准库的一部分,但我不太确定。

C++11、21.7

  1. 表 74、75、76、77、78 和 79 分别描述了标题<cctype><cwctype><cstring><cwchar><cstdlib>(字符转换)和<cuchar>

  2. 这些标头的内容应分别与标准 C 库标头<ctype.h><wctype.h><string.h><wchar.h><stdlib.h>以及 C Unicode TR 标头相同,并进行以下修改:

“以下修改”均未提及附加的保留标识符。表 74 是函数名称的分类列表,例如isdigitisalnum

C++11、C.2

1. 本小节总结了标准 C 库中包含的 C++ 标准库的内容。它还总结了其他子条款(17.6.1.2、18.2、21.7)中提到的标准 C 库中定义、声明或行为的显式更改。

7. C++标准库提供了来自C库的209个标准函数,如表153所示。

同样,表 153 是一个税收清单。

问题 2:假设我在问题 1 上错了,并且程序实际上在 C++ 中也有 UB,那么以下更改是否会影响这一点?

namespace foo {

  int issuecode(int i)
  {
    return 2 * i;
  }

}

using namespace foo;

int main(int argc, char **argv)
{
  return issuecode(argc);
}

注意:标准引用来自草案 N1256 (C99)、N1570 (C11) 和 N3242 (C++11),它们是各自语言版本的最新公开可用草案。

4

2 回答 2

1

为方便起见,以下名称分组在各个标题下。无论程序包含什么标头,下面描述的所有外部名称都是保留的。

有一个预定义的保留函数列表,如果您的函数在名称上没有冲突,则没有问题。

以 is 或 to 开头的函数名称和小写字母可以添加到 <ctype.h> 标头中的声明中。

可以将有效术语添加到<ctype.h>标题中。“是或到”位只是对声明组织的指导。

所以那里从来没有真正的未定义行为......

至于 C++,我认为这遵循相同的想法,例如:

namespace foo{
  int isupper ( int c );
}

#include <cctype>
using namespace foo;
int main(void){
    isupper(92);
}

这应该会产生编译器错误,因为您的函数与 C 函数的名称冲突,但由于命名空间,这很容易通过在调用的开头附加 anstd::或 a来修复。foo::

于 2013-07-06T16:38:28.937 回答
0

C++11 17.6.1.2 头文件

172) C 标准库头文件(附件 D.5)也定义了全局名称空间内的名称,而 C 库工具的 C++ 头文件(17.6.1.2)可以定义全局名称空间内的名称。

然而,在 C++ 标准库中,声明(在 C 中定义为宏的名称除外)在命名空间 std 的命名空间范围 (3.3.6) 内。未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明 (7.3.3) 注入命名空间 std。

因此,如果您不包括<cctype>该行为,则该行为是明确定义的。如果你这样做,它是未指定的。

于 2013-07-06T18:02:37.087 回答