用g++进行奇怪的零初始化

Strange zero initialization with g++

本文关键字:初始化 g++      更新时间:2023-10-16

在使用g++ 4.4.3进行int型初始化时,我遇到了下面代码的一个奇怪行为。

  int main()
    {
        int x(int());
        int y = int();
        cout << x << "  " << y <<  endl;
    }

的结果是:

1 0

"y"的值如预期的那样是0,但x的值奇怪地是"1"!

在VS2008中产生以下链接错误(函数声明,但没有定义):

unresolved external symbol "int __cdecl x(int (__cdecl*)(void))"
谁能解释g++的这种奇怪行为?

int x(int());解析为函数声明

声明一个名为x的函数,返回一个int,接受一个参数,该函数的类型为返回一个int,不接受任何参数。

为了补充GMan在这里的答案(x是一个函数定义),为什么1 .

输出为1的原因是,在调用std::cout << x的地方,函数衰减为指向该函数的指针(语言不允许将函数作为参数传递给其他函数,因此对于数组,执行隐式转换为指向的指针)。现在,没有接受函数指针的ostream的重载,编译器尝试选择到任何可用的重载的转换。此时,它发现最佳的转换序列是到bool,并打印1(指针不为0)。

您可以通过更改行为来检查这一点,您可以使用std::cout << std::boolalpha << x,这将打印true而不是1。此外,值得注意的是,VS在这一点上是正确的,因为表达式std::cout << x需要获取x的地址,那么该函数是使用的,如果该函数没有定义,则程序是病态的。您可以通过提供定义再次检查:

int f() {}
int main() {
   int x(int());      // 1
   x( &f );           // 2
}
int x( int(*)() ) {   // 3
   std::cout << "In x" << std::endl;
}

x(1)的定义和参数f(2)的调用中,我手动执行了从functionpointer-to-function的转换——请注意,1中的声明和3 中的定义是相同的签名,并且x( &f )中的&将由编译器执行,如果你不这样做。

添加更多的父元素:

int main()
    {
        int x((int()));
        int y = int();
        cout << x << "  " << y <<  endl;
    }

现在x是整型而不是函数

正如其他人所说,x是一个函数声明。由于没有为函数指针类型定义预定义的ostream插入器,g++似乎使用隐式bool转换(用于检查函数指针是否为NULL)来找到一种输出方法。

另一方面,Visual c++抱怨声明的函数x从来没有定义,因此它不能完成链接。我怀疑在这种情况下,g++足够聪明,可以看到函数从未被调用,因此不需要担心链接。

您可以尝试在代码中添加函数int x(int(*)()) { return 0xdeadbeef; }的虚拟定义,然后看看MSVC如何处理它。

c++将第一个解释为函数声明。

This

int x(int());

实际上是一个函数声明,输入是以下签名的函数

int fn(void)

传递给std::cout <<的函数指针被转换为bool(1),因为它是非null指针。