C keywords/functions 是否未包含在 C++ 中的 std 命名空间中?

Are C keywords/functions not enclosed in std namespace in C++?

以下代码在我的本地系统上运行良好,但在在线平台上出现编译错误。

#include <iostream>

int32_t time[int32_t(1e5)];

int main()
{
    int32_t n;
    std::cin>>n;
    for(int32_t i=0;i<n;++i)
    {
        int32_t temp;
        std::cin>>temp;
        --temp;
        ++time[temp];
    }
    
    return 0;
}

很明显,错误是因为第3行产生的int32_t time[int32_t(1e5)]; 但是,我无法理解为什么会出现编译错误。

我没有包含 ctime 或任何此类 header,甚至没有解包 std 命名空间。但是还是编译失败

我的系统上有 __cplusplus 201703 的 gcc 8.3.0。不知道线上平台是什么版本

您间接包含头文件 time.h。在此头文件中,有一个名为 time 的函数声明与您的声明冲突。

只需将变量 time 更改为另一个名称 (time_1)。

标准说,当您包含任何标准包含文件时,这可能会包含其他包含文件。具体是哪些以及有多少取决于实现。

这意味着您的代码不能定义任何也是标准的全局名称。

我能理解这似乎是一个困难的要求(确实如此),这也让人想知道为什么有标准的包含文件,而我们没有简单的整个标准可用(这是一个很好的问题) .但是none越少是这种情况。

POSIX 的情况更糟,不仅保留了随机名称,而且还保留了很多 prefixessuffixes;例如,以任何方式使用任何名称 startingLC_ 后跟大写字母的代码可能与与语言环境支持相关的 #defines 发生冲突。任何以 _t 结尾的名字也是保留的,不是开玩笑的。 The list is huge.

作为一般规则,尝试定义尽可能少的全局名称并避免使用标准库也使用的任何名称。即使在您的编译器上“有效”,您的程序在移植到另一个编译器(或同一编译器的下一个版本)时也可能会发现问题。避免定义全局名称还可以让您的代码更容易与其他人编写的代码集成到更大的程序中。理想情况下,您的代码应该只有一个全局名称(一个命名空间、一个 class 或一个函数)...不幸的是,对于 C++,您不能低于该名称。

我记得在编写小型 C++ 实验时碰到的东西,当时我通常不关心这些名称冲突问题,例如 y0 这是一个标准贝塞尔函数(这不是开玩笑;有全局标准函数 double y0(double) 和任何在全局级别使用 y0 的程序都不是有效的 C++ 程序)。

Are C keywords/functions not enclosed in std namespace in C++?

关键字(还有宏):不,它们不在命名空间中。

函数、类型和变量(即除宏之外的所有标识符):取决于您包含的标准header。

如果包含 C 标准 header,例如 <stdint.h>,则名称将位于全局命名空间中。它们也可能在 std 命名空间中,但不能保证。

如果包含相应的 <cstdint> header,则 C 标准 header 中的名称保证在 std 命名空间中。它们也可能在全局命名空间中,但这并不能保证。

您未能包含 <stdint.h><cstdint>,因此无法保证 int32_t 会在任一命名空间中声明。但是你已经包含了另一个标准 header 因此不能保证它不会在某些名称空间中声明 - 因为标准 headers 可能包含其他 headers;除非标准中有记录,否则您永远不应该依赖这种传递包含(以您的示例依赖它的方式)。

同样适用于 time 函数。您已经包含了一个标准 header,但不能保证它不会包含另一个声明 time 的标准 header。并且不能保证它不会在全局命名空间中。

无论您是否包含任何标准 header,C 标准库使用的所有名称都保留给全局名称空间中的语言实现。通过自己定义::time,你的程序的行为将是不确定的(允许UB编译失败,这是最好的结果)。

Can I be assured that there would be no problem with the name clashing if I declare variables in local space?

如果是time,是的。 C 标准名称(当然除了宏)仅在全局命名空间中保留。本地名称不在全局名称空间中;他们会影响全球的,这很好。也可以在您自己的自定义命名空间中定义这些。

宏名称以及某些标识符(例如包含双下划线的标识符)在所有名称空间中都保留。所有的宏名称都是大写的,所以很容易通过在名称中包含小写字符来避免它们。


为了避免与标准名称以及第三方库的名称冲突,应该只在全局命名空间中声明一个名称(除了 main):一个(希望是唯一的)包含所有其他命名空间的命名空间范围声明。并且应尽可能避免宏,但在必要时,它们应包含一些(希望是唯一的)前缀。