考虑下面的代码,这是我执行IRL(并且已经做过几次)的事情的简化版本,其中有一个“多余的”运算符地址,不应存在。
#define HEAD \
int type
struct my_struct {
HEAD;
};
struct my_struct_extended {
HEAD;
int a;
int b;
};
int my_function(const struct my_struct *data) {
return data->type;
}
struct my_struct_extended global = { 2, 3, 4 };
int main (int argc, char **argv) {
struct my_struct_extended *local = &global;
// ADDRESS-OF SHOULD NOT BE HERE \/
return my_function((struct my_struct *) &local);
}
有结构,一个基本结构和一个扩展结构。扩展结构的一个实例强制转换为要在my_function()
中使用的基本结构。但是,由于放错了地址的运算符,该功能基本上开始处理垃圾数据。
当您将双指针传递给需要单指针的函数时,编译器(在我的情况下为GCC)始终会发出警告,但是当需要强制转换结构时,会掩盖此类错误。我猜编译器将强制类型转换解释为“是!我真的很想要这个”或其他。
是否有可以用来捕获此警告的警告?
注意:实际情况是涉及struct sockaddr
的演员表:
ret = rrr_ip_send (
&err,
ip_data->ip_udp.fd,
// EXTRA ADDRESS-OF \/
(struct sockaddr *) &addr,
addr_len,
(void *) send_data,
send_size
);
通常,在不同的指针到结构类型之间没有强制转换的警告,因为显式强制转换的存在被视为对编译器的一条指令,即您知道自己在做什么并且不希望看到任何警告。
尽管如此,编译器仍然具有警告选项,可能在投射时发生未对准和溢出。
避免此错误的一种好的做法是,除非绝对必要,否则不要使用演员表。因此,使用该做法,您可能会写:
return my_function(&local);
然后得到编译器诊断,关于my_function
的参数中的类型不匹配。
这种用C语言进行继承的手工编码并不罕见,但是您确实需要非常小心,并定义函数以根据继承的类型指针或基本类型指针在层次结构中的位置严格使用。不幸的是,在您的示例中使用地址运算符的错字只是由于强制转换而可能隐藏在这些设计中的错误。减轻这种情况的一种方法是将所有的强制转换作为带有适当注释的单独的行表达式进行处理,例如:
#define HEAD \
int type
struct my_base_struct {
HEAD;
};
struct my_derived_struct {
struct my_base_struct base;
int a;
int b;
};
int my_base_function(const struct my_base_struct *self) {
return self->type;
}
struct my_derived_struct global = (struct my_derived_struct){ .base.type = 2 };
int main (int argc, char **argv) {
struct my_derived_struct *local_derived = &global;
// get base pointer
struct my_base_struct *base = (my_base_struct *)local_derived;
return my_base_function(base);
}
这将使其他人警觉到正在尝试的诡计。
BTW:sockaddr结构的重载是一个令人困惑的混乱根源。