C++中同名的C结构和C函数

C structure and C function with the same name in C++

当我混合使用 C 和 C++ 代码时,当 Linux C 结构 statxstatx() Linux 系统同名时,我 运行 遇到了问题打电话。

对于安装的 glibc 版本中不存在 statx() 系统调用的情况,我实现了自己的 statx() 版本。我尝试在匿名命名空间中实现替代 statx() 函数,但在这种情况下代码无法编译。

我试图将示例代码简化到最低程度。

#include <iostream>

struct statx {};

namespace {

void statx() { std::cout << "Function statx()\n"; }

}

int main()
{
    statx();    // Compile error.
    ::statx();  // Calling constructor of struct instead of function statx().
}

用g++8编译的输出结果

g++ -std=c++17 -Wall -pedantic -Wextra str_fnc.cpp -o str_fnc


str_fnc.cpp: In function 'int main()':
str_fnc.cpp:13:5: error: reference to 'statx' is ambiguous
   13 |     statx();    // Compile error.
      |     ^~~~~
str_fnc.cpp:7:6: note: candidates are: 'void {anonymous}::statx()'
    7 | void statx() { std::cout << "Function statx()\n"; }
      |      ^~~~~
str_fnc.cpp:3:8: note:                 'struct statx'
    3 | struct statx {};
      |        ^~~~~
str_fnc.cpp: At global scope:
str_fnc.cpp:7:6: warning: 'void {anonymous}::statx()' defined but not used [-Wunused-function]
    7 | void statx() { std::cout << "Function statx()\n"; }
      |      ^~~~~

当我使用静态函数 statx() 而不是将其包含在匿名命名空间中时,代码编译并成功运行。

#include <iostream>

struct statx {};

static  // The replacement anonymous namespace with static function.
void statx() { std::cout << "Function statx()\n"; }

int main()
{
    statx();
    ::statx();
}

谁能解释为什么匿名命名空间中包含 statx() 的示例无法编译且无法运行?

Name hiding [basic.scope.hiding]
2. If a class name ([class.name]) or enumeration name ([dcl.enum]) and a variable, data member, function, or enumerator are declared in the same declarative region (in any order) with the same name (excluding declarations made visible via using-directives ([basic.lookup.unqual])), the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

因此在您的第二个示例中,两个名称在同一声明区域中声明,并且该函数隐藏了结构名称。 (您仍然可以通过其详细类型说明符 struct statx 引用该结构)。

在第一个示例中,函数是在不同的声明区域中引入的,因此此规定不适用。相反,正常的命名空间规则生效。也就是说,内部名称就像通过 using 声明一样被带到全局范围。如果在未命名命名空间的内部和外部都声明了相同的名称,则该名称在不合格时会变得不明确。您可以 select 带有 :: 的外部名称,但是无法从未命名的命名空间外部引用内部名称。