为什么gcc 4.7.0在这个代码上给了我一个segfault,而在线视频(gcc 4.5.1)没有

Why is gcc 4.7.0 giving me a segfault on this code while online ideone(gcc 4.5.1) doesnt?

本文关键字:gcc segfault 一个 在线视频 没有 代码 为什么      更新时间:2023-10-16

我有以下代码(仅适用于gcc):

#include <iostream>
#include <cstdlib>
#include <string>
#include <typeinfo>
#include <cxxabi.h>
const std::string demangle (const char* name) {
    int status = -4;
    char* res = abi::__cxa_demangle(name, 0, 0, &status);
    const char* const demangled_name = (status == 0) ? res : name;
    std::string ret_val(demangled_name);
    std::free(res);
    return ret_val;
}
template <typename T>
const std::string getname (T x)
{
    return demangle(typeid(x).name());
}
int main()
{
   std::add_const<int>::type *p = static_cast<const int *>(0); 
   std::cout << getname(*p) << std::endl;
}

在我的本地计算机上(使用gcc 4.7.0(实验性),它崩溃了(使用gdb运行会产生segfault)。然而,使用ideone.com,它可以按预期打印"int"。下面是示例链接。此外,去掉模板并调用demangle(typeid(x).name())直接解决了问题,那么模板有什么问题呢?

编辑我忘了包含解决问题的type_traits标头(doh!),但我仍然想更好地了解发生了什么。

std::add_const<int>::type *p = static_cast<const int *>(0); 

p是一个空指针,对其进行去引用(即*p)调用会产生未定义的行为(UB)。你很幸运,它给了segfault。由于它实际上是UB,所有编译器(和所有版本)都可能不会给出segfault,因为这就是UB的意思,即任何事情都可能发生。

你为什么不试试这个呢:

std::cout << getname(int()) << std::endl;

这里有一个微妙的问题:这是一个评估问题。

通常,取消引用空指针是未定义的行为;然而,有一种极端情况(至少在gcc上),即在p为null的情况下调用typeid(*p)是有效的表达式。

因此,这里的问题在于您的间接级别:

int* p = 0;
getname(*p);       // p is null, *p invokes undefined behavior
typeid(*p).name(); // p is null, but it's probably okay in `typeid`
                   // because it's an unevaluated operand here

对于那些有兴趣深入研究的人,typeid表达式在§5.2.8(C++11)中有详细描述。

2/typeid应用于类型为多态类类型(10.3)的glvalue表达式时,结果指代std::type_info对象,该对象表示glvalue所指的最派生对象(1.8)(即动态类型)的类型。如果glvalue表达式是通过将一元*运算符应用于指针而获得的,并且指针是空指针值(4.10),则typeid表达式抛出std::bad_typeid异常(18.7.3)

好的,如果p指向多态类,那么定义typeid(*p)。。。在这种情况下,它会抛出。

3/typeid应用于多态类类型的glvalue以外的表达式时,结果指代表示该表达式的静态类型的std::type_info对象。Lvalue到右值(4.1)、数组到指针(4.2)和函数到指针(4.3)的转换不应用于表达式。如果表达式的类型是类类型,则应完全定义该类。表达式是未赋值的操作数(第5条)。

有趣的是,没有提到非多态类的空指针。我怀疑未赋值的操作数是允许这样做的原因,但尚未找到引文。

6/如果在使用typeid之前未包含标头<typeinfo>(18.7.1),则程序格式不正确。

似乎不需要诊断。至少在gcc上,我认为这是一个警告。