代码之家  ›  专栏  ›  技术社区  ›  CPlus

在用户定义的令牌后#包含文件是否存在潜在问题?

  •  1
  • CPlus  · 技术社区  · 2 年前

    由于预处理器的工作方式,包含的头文件可能会受到包含头的文件的影响。例如,您可以仅使用以下命令中断C:

    #define printf
    #include <stdio.h>
    /*  extern int printf(const char *const restrict format, ...);
        Becomes
        extern int (const char *const restrict format, ...);
        And this results in an instant syntax error */
    

    然而,我担心任何随机的用户定义标识符都可能以类似的方式破坏特定实现的头文件。但可以预期库头文件永远不会相互破坏,因为这样C实现就会完全破坏,从而不一致。因此,我一直很小心地将库标头始终保持在顶部:

    #include <stdio.h>
    #include <somelibrary.h>
    
    #define some_macro
    typedef some_type some_other_type;
    

    而不是:

    #define some_macro
    typedef some_type some_other_type;
    
    #include <stdio.h>
    #include <somelibrary.h>
    

    因为如果其中一个库恰好包含标记 some_macro some_other_type 它们可能会断裂。

    这些担忧是否合理?或者C要求可以 “中断” 库标头在某种程度上被限制为仅由标头定义的用户可见的标头?

    2 回复  |  直到 2 年前
        1
  •  2
  •   Andrew Henle    2 年前

    我担心任何随机的用户定义标识符。。。

    C的概念是 reserved identifiers (粗体字):

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

    如果程序在保留标识符的上下文中声明或定义标识符(7.1.4允许的情况除外),或者 将保留标识符定义为宏名称,行为未定义

    标识符C保留由C标准来标识。

    此外,POSIX等平台 reserve additional identifiers ,Windows也这样做- some of which can be found here -但是有一个 大量 Windows保留的更多标识符。

    注意上面的第二句话,尤其是粗体部分:

    如果程序在保留标识符的上下文中声明或定义标识符(7.1.4允许的情况除外),或者 将保留标识符定义为宏名称,行为未定义

    是的,如果您使用保留的标识符,您可以也将破坏您的程序。

    解决方法:不要这么做。

    例如,这是一个保留的标识符:

    __SOMETHING

    它以双下划线开头,因此它是一个保留标识符。不要那样做。

    这也是POSIX下的一个保留标识符:

    something_t

    它以结尾 _t ,这是在POSIX下保留的。不要那样做。(很多人打破了这个,有时他们后来会遇到问题。不要依赖你的 _t 标识符是碰撞安全的。)

    在文件范围内,这是一个保留的标识符:

    static int _count;

    它以下划线开头。这是文件范围内的保留标识符。不要那样。(这里也是一样——很多程序员打破了这条规则,认为自己逃脱了惩罚——他们只是运气好。不要把运气作为 你的 代码正常工作…)

    许多程序员使用保留的标识符,不会遇到冲突,所以他们认为这样做是可以的。但它们在未来毫无理由地面临碰撞和断裂。

        2
  •  2
  •   Allan Wind    2 年前

    有些库有条件地定义符号。 __POSIX_SOURCE _POSIX_C_SOURCE 是我最常遇到的人,但还有很多其他人。有一套大的、令人困惑的 reserved identifiers (namespaces) 根据@someprogrammerdue,您不应该使用它来避免未定义的行为。另请参阅 C 2017 7.1.3.例如 _ 前缀和 _t 后缀是保留的,但我经常在用户代码中看到它。

    推荐文章