在GCC没有的情况下,Clang会发出非法指令

Lem*_*ing 14 c++ clang

我发现了一种情况,在这种情况下,Clang会产生非法指令,gcc没有这样做,同时试验这个问题.

我的问题是:我做错了什么,或者这是Clang的实际问题?

我把它归结为重现问题所需的最小片段.

拿文件eigen.cpp:

#include <iostream>

#define EIGEN_MATRIXBASE_PLUGIN "eigen_matrix_addons.hpp"
#include <Eigen/Dense>

int main() {
    Eigen::Matrix2d A;

    A << 0, 1, 2, 3;

    std::cout << A << "\n";
}
Run Code Online (Sandbox Code Playgroud)

和文件eigen_matrix_addons.hpp:

friend std::ostream &operator<<(std::ostream &o, const Derived &m) {
    o << static_cast<const MatrixBase<Derived> &>(m);
}
Run Code Online (Sandbox Code Playgroud)

(有关此文件的详细说明,请参见此处.简而言之,其内容直接放在类的定义中template<class Derived> class MatrixBase;.因此,这会引入另一个ostream运算符Derived,调用ostream运算符的Eigen实现MatrixBase<Derived>.此动机为此如果你读这个问题就会变得很明显.)

使用GCC编译并运行:

$ g++ -std=c++11 -Wall -Wextra -pedantic -isystem/usr/include/eigen3 -I. -o eigen_gcc eigen.cpp
$ ./eigen_gcc
0 1
2 3
$ g++ --version
g++ (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)

然后用Clang编译并运行:

$ clang++ -std=c++11 -Wall -Wextra -pedantic -isystem/usr/include/eigen3 -I. -o eigen_clang eigen.cpp
$ ./eigen_clang
0 1
Illegal instruction
$ clang++ --version
clang version 3.4 (branches/release_34 198681)
Target: x86_64-suse-linux
Thread model: posix
Run Code Online (Sandbox Code Playgroud)

如您所见,程序在执行非法指令后被中断.gdb中的反向跟踪显示问题发生在以下第二行eigen_matrix_addons.hpp:

(gdb) bt
#0  0x00000000004013e1 in Eigen::operator<< (o=..., m=...)
    at ./eigen_matrix_addons.hpp:2
#1  0x00000000004010f0 in main () at eigen.cpp:15
Run Code Online (Sandbox Code Playgroud)

也许是static_cast

根据我的Eigen版本是3.2.0-2.1.4 zypper.

编辑

@Mysticial要求的拆卸:

(gdb) disass
Dump of assembler code for function Eigen::operator<<(std::ostream&, Eigen::Matrix<double, 2, 2, 0, 2, 2> const&):
   0x00000000004013c0 <+0>:     push   %rbp
   0x00000000004013c1 <+1>:     mov    %rsp,%rbp
   0x00000000004013c4 <+4>:     sub    $0x20,%rsp
   0x00000000004013c8 <+8>:     mov    %rdi,-0x10(%rbp)
   0x00000000004013cc <+12>:    mov    %rsi,-0x18(%rbp)
   0x00000000004013d0 <+16>:    mov    -0x10(%rbp),%rdi
   0x00000000004013d4 <+20>:    mov    -0x18(%rbp),%rsi
   0x00000000004013d8 <+24>:    callq  0x4013f0 <Eigen::operator<< <Eigen::Matrix<double, 2, 2, 0, 2, 2> >(std::ostream&, Eigen::DenseBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> > const&)>
   0x00000000004013dd <+29>:    mov    %rax,-0x20(%rbp)
=> 0x00000000004013e1 <+33>:    ud2
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

小智 24

"非法指令"错误可能是因为您的"operator <<"缺少return语句.这导致未定义的行为.

标准第6.6.3节说:

流出函数末尾相当于没有值的返回; 这会导致值返回函数中的未定义行为.

你应该添加:

return o;
Run Code Online (Sandbox Code Playgroud)

在功能的最后.

  • 你也可以`return o << ...;`把它保持在一行. (4认同)