我正在尝试为两个不同的Linux环境构建一个简单的C程序.在一个设备上程序运行正常,在另一个设备上程序生成浮点异常.该程序什么都不做,但从main返回0,这让我相信可能与启动代码ABI有一些不兼容?
该程序使用gcc编译,具有以下构建规范:
使用内置规格.目标:i386-redhat-linux配置:../ configure --prefix =/usr --mandir =/usr/share/man --infodir =/usr/share/info --enable-shared --enable-threads = posix --enable-checking = release --with-system-zlib --enable -__ cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages = c,c ++,objc,obj-c ++ ,java,fortran,ada --enable-java-awt = gtk --disable-dssi --disable-plugin --with-java-home =/usr/lib/jvm/java-1.4.2-gcj-1.4. 2.0/jre --with-cpu = generic --host = i386-redhat-linux线程模型:posix gcc版本4.1.2 20080704(Red Hat 4.1.2-52)
程序源如下:
int main()
{
return(0);
}
Run Code Online (Sandbox Code Playgroud)
在Celeron设备上,该程序在GDB下生成以下内容:
[root@n00200C30AA2F jrn]# /jrn/gdb fail GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) (gdb) run Starting program: /jrn/fail
Program received signal SIGFPE, Arithmetic exception. 0x40001cce in ?? () (gdb) …Run Code Online (Sandbox Code Playgroud) 我有一个小程序执行零浮点除法,所以我期待SIGFPE.
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
void signal_handler (int signo) {
if(signo == SIGFPE) {
std::cout << "Caught FPE\n";
}
}
int main (void) {
signal(SIGFPE,(*signal_handler));
double b = 1.0;
double c = 0.0;
double d = b/c;
std::cout << "d = "<< d << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
实际上,我得到了以下输出:
d = inf
Run Code Online (Sandbox Code Playgroud)
gcc版本4.5.2(Ubuntu/Linaro 4.5.2-8ubuntu4)
在这种情况下,我应该怎么做才能抛出SIGFPE?FP操作行为依赖于哪些因素(编译器标志/ CPU类型等)?
谢谢
我是Linux信号的新手,请帮忙.以下代码在Linux 2.6 gcc中运行时获得核心转储.
$ ./a.out
浮点异常(核心转储)
问题:
1.由于安装了过程信号掩码,第40行(z = x/y)生成的"SIGFPGE"是否应该被阻止?
2.如果没有阻塞,由于已经安装了信号处理程序,信号处理程序不应该捕获"SIGFPE"而不是核心转储?
3.如果我注释掉第40行(z = x/y),并使用第42行(加注(SIGFPE)),那么一切都按预期工作.这里x/0和提升SIGFPE有什么区别?
这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sig_handler(int signum)
{
printf("sig_handler() received signal %d\n", signum);
}
int main(int argc, char * argv[])
{
// setup signal mask, block all signals
sigset_t set;
sigfillset(&set);
if(sigprocmask(SIG_BLOCK, &set, NULL)<0)
{
perror("failed to set sigmask");
return -1;
}
// install signal handler for SIGFPE
struct sigaction act;
act.sa_handler = sig_handler;
act.sa_mask = set;
act.sa_flags = 0;
if(sigaction( SIGFPE, &act, …Run Code Online (Sandbox Code Playgroud) 我有一个数千行的应用程序,依赖于SIGFPE(由传递给signal()的函数指针处理)来改变状态,并在某些浮点条件发生时使代码正确运行.但是,在托管模式下的C++/CLI下,_control87会生成在用C编写的静态库中执行的System.ArithmeticException.不支持_fpreset和_control87.
如何在C++/CLI应用程序中使用经典的非托管SIGFPE操作?在我的应用程序中发生浮点内容的位置数量可能是巨大的,我不完全理解其他程序员多年前编写的所有数值方法.
我希望老式异常处理能够将浮点除法用于零,而不是INF值.平台调用样式不起作用,#pragma managed(off)也不起作用.
我有什么选择?
为什么SIGFPE用于整数算术异常,例如除以零,而不是为整数算术异常创建单独的信号或通常首先为算术异常命名信号?
好吧,我搜索了有关SIGFPE的文章,然后我写了一些测试,但它的行为很奇怪.然后我必须在这里发帖寻求帮助.GCC/G ++或ISO C++是否明确定义了如果除以零会发生什么?
1)我搜索了这篇文章: 除零之后不会抛出SIGFPE 同样输出是inf
2)如果我重写如下:
void signal_handler (int signo) {
if(signo == SIGFPE) {
std::cout << "Caught FPE\n";
}
}
int main (void) {
signal(SIGFPE,(*signal_handler));
int b = 1;
int c = 0;
int d = b/c;
//fprintf(stderr,"d number is %d\n,d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后signal_handler将不会发生.但如果我取消注释该行
//fprintf(stderr,"d number is %d\n,d);
Run Code Online (Sandbox Code Playgroud)
然后signal_handler继续打电话.
有人可以解释一下吗?
我读到这个和这个.如果通过包含fenv.h生成nan并且启用所有浮点异常,则可以抛出SIGFPE,但是FE_INEXACT通过feenableexcept(FE_ALL_EXCEPT & ~FE_INEXACT);
因此,代码改变了形式
int main () {
double dirty = 0.0;
double nanvalue = 0.0/dirty;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
至
#include <fenv.h>
int main () {
feenableexcept(FE_ALL_EXCEPT & ~FE_INEXACT); // Enable all floating point exceptions but FE_INEXACT
double dirty = 0.0;
double nanvalue = 0.0/dirty;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,但您必须更改代码.我有问题,在一个巨大的c和c ++代码库中,某个地方生成了一个nan,我不知道在哪里.将上述更改应用于文件的hunderts并跟踪错误不是一种选择.
有没有办法在没有代码更改的情况下启用所有浮点异常?有没有我不知道的编译选项?
我们使用intel icc 15.0.3版编译器.
我喜欢在启用浮点异常的情况下运行我的代码。我在 Linux 下使用:
feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好。
我遇到的问题是,有时编译器(我使用 clang8)决定使用 SIMD 指令进行标量除法。好吧,如果这更快,即使对于单个标量,为什么不呢。
但结果是 SIMD 寄存器中未使用的通道可能包含零。
并且在执行 SIMD 除法时,会抛出浮点异常。
这是否意味着如果允许编译器使用 sse/avx 扩展,则根本无法使用浮点异常?
就我而言,这行 C 代码:
float a0, min, a, d;
...
a0 = (min - a) / (d);
Run Code Online (Sandbox Code Playgroud)
...被执行为:
divps %xmm2,%xmm3
Run Code Online (Sandbox Code Playgroud)
然后抛出一个:
Thread 1 "noisetuner" received signal SIGFPE, Arithmetic exception.
Run Code Online (Sandbox Code Playgroud) 目前我正在学习浮点异常。我正在写一个带有函数的循环。在该函数中,计算出的值等于0.5。随着循环的进行,输入值除以10。
循环:
for(i = 0; i < e; i++)
{
xf /= 10.0; // force increasingly smaller values for x
float_testk (xf, i);
}
Run Code Online (Sandbox Code Playgroud)
功能:
void float_testk(float x, int i)
{
float result;
feclearexcept(FE_ALL_EXCEPT); // clear all pending exceptions
result = (1 - cosf(x)) / (x * x);
if(fetestexcept(FE_UNDERFLOW) != 0)
fprintf(stderr,"Underflow occurred in double_testk!\n");
if(fetestexcept(FE_OVERFLOW) != 0)
fprintf(stderr,"Overflow occurred in double_testk!\n");
if(fetestexcept(FE_INVALID) != 0)
fprintf(stderr,"Invalid exception occurred in double_testk!\n");
printf("Iteration %3d, float result for x=%.8f …Run Code Online (Sandbox Code Playgroud) 我重复相同的计算两次,但在一次我得到一个浮点异常,而在另一个我没有.
#include <iostream>
#include <cmath>
#include <fenv.h>
using namespace std;
int main(void)
{
feenableexcept(-1);
double x,y,z;
x = 1.0;
y = (1.0/(24.3*24.0*3600.0))*x;
cout << "y = " << y << endl;
z = x/(24.3*24.0*3600.0);
cout << "z = " << z << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我在g ++和clang ++上测试了它,并在两者中得到了以下输出
y = 4.76299e-07
Floating point exception
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?