我的代码:
#include "xception.h"
#include <iostream>
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>
#include <execinfo.h>
void bt_sighandler(int sig, struct sigcontext ctx)
{
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *)ctx.eip;
messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:\n");
for (i=1; i<trace_size; ++i)
{
printf("[bt] #%d %s\n", i, messages[i]);
char syscom[256];
sprintf(syscom,"addr2line %p -e sighandler", trace[i]);
system(syscom);
}
}
void xception::initialize_xception()
{
/* Install our signal handler */
struct sigaction sa;
sa.sa_handler = (void *)bt_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &sa, NULL);
}
这给了我错误:r@r-HP-Mini-110:~/l33t/freeln/Xception/source$ g++ -std=c++11 -g -rdynamic -Wall -o xcep_app application.cpp xception.cpp
xception.cpp: In static member function ‘static void xception::initialize_xception()’:
xception.cpp:38:28: error: invalid conversion from ‘void*’ to ‘__sighandler_t {aka void (*)(int)}’ [-fpermissive]
奇怪的是,早期编译的内容如下所示:
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>
#include <execinfo.h>
void bt_sighandler(int sig, struct sigcontext ctx)
{
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *)ctx.eip;
messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:\n");
for (i=1; i<trace_size; ++i)
{
printf("[bt] #%d %s\n", i, messages[i]);
char syscom[256];
sprintf(syscom,"addr2line %p -e sighandler", trace[i]); //last parameter is the name of this app
system(syscom);
}
}
int func_a(int a, char b) {
char *p = (char *)0xdeadbeef;
//a = a + b;
//*p = 10; /* CRASH here!! */
a =9;
return 2*a;
}
int func_b() {
int res, a = 5;
res = 5 + func_a(a, 't');
raise(SIGUSR1);
return res;
}
int main() {
/* Install our signal handler */
struct sigaction sa;
sa.sa_handler = (void *)bt_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
//sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
/* ... add any other signal here */
/* Do something */
printf("%d\n", func_b());
printf("%s\n", "not dead yet :)");
}
你能指出我的错误吗?
答案 0 :(得分:5)
无论您如何切片,都不能使用
void bt_sighandler(int sig, struct sigcontext ctx)
在需要void (int)
回调的地方运行。您可以通过使用强制转换来成功地抑制错误消息,这将使代码正式“编译”,但这不会使您的程序在任何有意义的“工作”一词中起作用。
sa.sa_handler
回调函数必须是void (int)
函数,句点。没有办法绕过它。如果您想将一些额外的外部数据“走私”到该功能中,您必须创建一个替代解决方案。您不能只是向回调函数添加任意参数,并期望调用者以某种方式神奇地为您添加的参数提供正确的参数。
答案 1 :(得分:1)
sa_handler
的{{1}}成员是struct sigaction
类型的函数指针。相比之下,表达式void(*) (int)
的类型由于演员而为(void *)ctx.eip
。在C ++中,不会发生从void *
到另一个指针类型的隐式转换,因此会出错。
答案 2 :(得分:1)
不同之处在于,在 C 中,您可以隐式地将void *
转换为任何其他指针类型,而在 C ++ 中则不能。
在 C ++ 中,您需要对实际函数类型(void (*)(int)
)进行显式强制转换,以使其不是错误。
请注意,在 C 和 C ++ 中,将void *
转换为函数指针是未定义的行为,但如果void *
通常会有效首先从兼容的函数指针转换。另外,如果所有参数类型完全相同,则只保证函数指针是完全兼容的,尽管你经常会得到一些似乎适用于不同参数类型的东西(未定义的行为)。