【问题标题】:Unexpected behaviour of std::cout [duplicate]std::cout 的意外行为 [重复]
【发布时间】:2017-08-14 11:21:46
【问题描述】:

我最近在玩函数指针,当时我发现std::cout 打印的函数指针的值总是计算为 1。

但是printf() 的情况并非如此,它会打印出预期的结果。

如果有人能解释这种行为背后的原因,那就太好了。

以下是代码示例供参考。

#include<iostream>

using namespace std;

int  fun(int a)
{
    return 0;
}

int main()
{

    cout<<(&fun)<<endl; //always prints 1
    printf("%u",&fun); //this prints the expected result

    return 0;
}

【问题讨论】:

  • g++: 警告:'int fun(int)' 的地址将始终评估为'true'
  • 看起来cout 不知道指向您的函数的指针类型,并将其转换为boolean
  • 另外,"%u" 不是地址的正确 printf() 格式说明符,因此是未定义的行为。 void * 的正确格式说明符是 %p,因此您必须转换为 void *
  • 如果您使用 printf,您可能需要包含正确的标题
  • 哪个编译器cout 打印1?尝试其他编译器上的代码,你会得到不同的结果。我猜是UB。

标签: c++ function-pointers


【解决方案1】:

printf 调用只是未定义的行为。函数指针不是无符号整数,因此为 %u 参数提供它是无效的。 (尝试在 64 位平台上运行此代码。您不会得到正确的函数指针值。)

另一方面,cout 是类型安全的。编译器看到一个函数指针参数并试图找到它可以找到的最佳打印函数(operator&lt;&lt; 重载)。函数指针本身没有这种重载,并且指针不提供很多隐式转换。只有一个重载有效,那就是bool。所以编译器将非NULL 函数指针转换为true 并传递它。然后重载将其打印为1,但您可以使用std::boolalpha 修饰符将其打印为true

【讨论】:

    【解决方案2】:

    您的 cout(&amp;fun) 视为布尔表达式,并警告它的计算结果将始终为 true(即非零)。

    尝试将其转换为void*,因为应该打印地址,然后检查会发生什么:

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    
    int  fun(int a){
        return 0;
    }
    
    int main(){
    
        cout<<(void*)(&fun)<<endl; //always prints 1
    
        /* Side note: This will print the same as above */
        // cout<<(void*)(fun)<<endl;  // note the missing &
    
        printf("%p",(void*)&fun); //this prints the expected result
        // while(1);
        return 0;
    }
    

    在 mu 机器上输出:

    0x401460
    0x401460
    

    【讨论】:

    • 你为什么有while(1);
    • 我用它来确保打开cmd窗口执行时不会关闭它
    • 这应该是你的环境的责任,而不是你的程序。严格来说,像这样的无限循环就是UB。
    • pause 命令在批处理文件中,例如。
    • Infinite loop ub 怎么样?