我有一个用C编写的回调函数,它在服务器上运行并且必须是防撞证明。也就是说,如果期望一个整数并传递一个字符串指针,我必须在函数内部确定,并防止在尝试对不正确的参数类型执行不允许的操作时出现Segmentation错误。
函数原型是:
void callback_function(parameter_type a, const b);
和'a'应该通过枚举告诉我'b'是整数还是字符串指针。 如果调用函数程序员犯了一个错误,并在'a'中告诉我'b'是一个整数,并且'b'实际上是一个字符串指针,那么如何在不崩溃回调函数代码的情况下确定它。这在服务器上运行,如果调用者函数出错,必须继续运行。
代码必须是C语言,并且是可移植的,因此不可能使用C库扩展。编译器是:gcc v4.8.2 平台上的整数大小为4,字符指针的长度也是4。 整数可以在数字上与字符指针具有相同的值,反之亦然。
如果我认为我得到一个字符指针而不是它,当我试图找到它的内容时,我当然会得到一个分段错误。
如果我写一个信号处理程序来处理故障,我现在如何“清除”信号,并在理智的地方恢复执行?
我是否提到'b'是一个定义为的联盟:
union param_2 {
char * c;
int i;
} param_to_be_passed;
我认为就是这样。
感谢您的回答。
答案 0 :(得分:1)
这是不可能的。
没有办法"看" at指针并确定它是否有效取消引用,但NULL
除外 - 当然要检查它。
除此之外,没有神奇的方法可以知道指针是指向字符数据,整数,函数还是其他任何东西。
答案 1 :(得分:1)
你正在寻找黑客。
什么提议来了,不要在生产中使用这些东西。
如果需要后期绑定,请采用不同的,自动防故障方法。
答案 2 :(得分:0)
如果您正在为嵌入式设备编写代码,您可能希望所有变量都驻留在RAM中。例如,从地址0x20000000
到0x20020000
可能有128 kB的RAM。如果你传递了一个指向没有这个范围的内存地址的指针,关于c
,除了检查一个NULL地址之外,这将是另一种确定错误的方法。
if((a == STRING) && ((b.c == NULL) || (b.c < 0x20000000) || (b.c > 0x20020000)))
return ERROR;
如果您在多线程环境中工作,您可以更进一步,并且要求传递给callback_function
的所有地址都来自某个线程的内存空间(堆栈)。
答案 3 :(得分:0)
C中的运行时类型检查实际上是不可能的。
调用者负担正确传递数据;没有(好的,标准的,可移植的)方式来确定b
是否包含正确类型的数据(即,调用者没有将指针值作为整数传递给你,反之亦然)。 / p>
我唯一可以建议的是创建两个单独的回调,其中一个回调采用int
而另一个采用char *
,并且在编译时将负担放在编译器上进行类型检查。
答案 4 :(得分:0)
注意:这实际上并没有尝试使该功能“防崩溃”,因为我怀疑那是不可能的。
如果允许您更改API,一个选项可能是组合联盟仅使用api来访问该类型。
typedef enum Type { STRING, INT } Type;
typedef struct StringOrInt {
Type type;
union { int i; char* s } value;
} StringOrInt;
void soi_set_int(StringOrInt* v, int i) {
v->type = INT;
v->value.i = i;
}
void soi_set_string(StringOrInt* v, char* s) {
v->type = STRING;
v->value.s = s;
}
Type soi_get_type(StringOrInt cosnt* v) {
return v->type;
}
int soi_get_int(StringOrInt const* v) {
assert(v->type == INT);
return v->value.i;
}
char* soi_get_string(StringOrInt const* v) {
assert(v->type == STRING);
return v->value.s;
}
虽然这实际上并没有使其成为防撞证明,但API的用户会发现使用API比手动更改成员更方便,从而大大减少了错误。
答案 5 :(得分:0)
如果来电者在a
中说结果为int
,则不会有很大的崩溃风险,因为:
在你的情况下,两种类型都有相同的长度(请注意,这不保证是便携式的!)
C标准说(ISO - sect.6.3.2.3):“任何指针类型都可以转换为整数类型。除了之前指定的,结果是实现定义的。如果结果无法表示在整数类型中,行为未定义。
但幸运的是,大多数32位值都是有效整数。
请记住,在最坏的情况下,价值可能毫无意义。因此,您可以通过系统地验证值的一致性来避免崩溃(例如,如果使用整数来对某些数组元素进行处理,请执行绑定控件)
如果调用者在“a”中说结果是指针但是提供了int,则以可移植的方式避免崩溃要困难得多。
标准ISO说:整数可以转换为任何指针类型。除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。
实际上,大多数这些错误都会被系统级别非常低的内存访问异常所困。正在实现的行为定义,没有可行的方法。