2013-07-06 30 views
14

把这个代码:有多大?C标准库扩展影响C++程序?

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)

与任一isto,和一个小写字母可被添加到的声明在<ctype.h>开始函数名头。

C99,7.1.3(或C11,7.1.3)

  1. 每个头声明或定义在其相关联的子条款中列出的所有的标识符,并且任选地声明或定义中列出的标识符在其相关联的未来图书馆方向款,以及它们总是保留要么用于任何用途或用作文件范围标识符的标识符。

    [...]

    • 以任何以下小节(包括未来图书馆方向)的外部链接的所有标识符总是保留用作具有外部链接标识符。
  2. [...]如果程序声明或定义在上下文中(由7.1.4所允许比其他)的标识符,其中它被保留,或者保留的标识符定义为宏名称,行为是不确定的。

基于上述,我认为函数名issuecode实际上是保留用于<ctype.h>,所以程序在技术上有UB。

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

问题1:将程序有UB如果编译为C++代码?

我相信答案是“不”,从下面的引用中,我会说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是一个taxative列表。

问题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),这是用于各个语言的最新公开可用的草稿所采取版本。

+0

0.校验和匹配。 1.我认为是,C++标准库**包含所有C标准库(甚至是旧的,不推荐使用的.h头文件)作为子集**。 2.我再次认为是,因为你现在不在'std ::'命名空间中。 (尽管如此,最好的方法是在DS9K上进行测试。) – 2013-07-06 15:58:26

+1

+1,但是......认真吗?包含名称以“is”开头的函数的C++程序具有UB?如果是这样,我一直在写UB ...... –

+0

@AndyProwl那些是我读完C标准部分时的想法。这就是为什么我反问这个问题的原因。从技术上讲,它只是非静态的全局函数;所有更多的理由使用命名空间;-) – Angew

回答

1

为方便起见,以下名称被分组到各个标题下。下面描述的所有外部名称不管该程序包括哪些头保留。

有一个预定义的函数列表,如果你的函数不冲突名称明智没有问题。与任一被或开始

函数名,和一个小写字母可被添加到的声明在<文件ctype.h >报头。

手术术语有可能被添加到<ctype.h>报头。 “是或是否”位只是组织声明的指导。

因此,有没有真正为未定义行为有...

至于C++,我认为这遵循了同样的想法举个例子:

namespace foo{ 
    int isupper (int c); 
} 

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

,因为你的函数碰撞时应该产生一个编译器错误使用C函数名称明智,但由于命名空间的原因,可以通过在呼叫开始时追加std::foo::来轻松解决此问题。

+0

我不认为你是正确的有一个“预定义的函数列表”。 7.26(“未来图书馆方向”)大部分与前缀“is”或“to”相同。例如。 “以'E'和一个数字开始的宏',”“以'int'或'uint'开头并以'_t'结尾的Typedef名称。”如果这些条款不是规范性的,那么这个条款几乎毫无意义,并且与第一段几乎相矛盾。 – Angew

+0

我发现他们不太可能在规范中留下如此大的UB漏洞,特别是在开发人员很可能具有'toFoo'功能的这种显而易见的动词功能中,这样做很愚蠢。 – Mgetz

+0

我同意这听起来有点太大了一堆名字要保留。也许意图的含义是“如果实现添加了这样的名称,即使未包含头部,它们也是保留的?”它不会以这种方式读取,但可能会更有意义... – Angew

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>行为是明确的。如果你这样做,它是不明确的。

+0

如果C99 7.26 appliesto C++,它独立于头包含(7.26要求)。如果不适用,那么在C++中不能使用UB,因为''不会保留这些附加名称。所以在某种程度上,我的问题的核心是C99 7.26是否适用于C++。 IOW,什么“这些名字”(来自你的报价)是。我不认为这个报价解决了这个问题。 – Angew