我一直在研究一些类似于以下内容的代码:
typedef struct
{
unsigned char x;
unsigned short y;
unsigned char[NUM_DEFINED_ELSEWHERE];
} My_Struct;
static My_Struct my_useful_struct; // Variables initialized elsewhere in code.
void myFunction(const My_Struct * p_my_struct)
{
/* Performs various read-only actions utilizing p_my_struct. */
}
void myOtherFunction(void)
{
static My_Struct * p_struct = &my_useful_struct;
myFunction(p_struct);
}
我的代码编译没有任何问题,但在审核时我被告知,除非我强调p_struct这可能导致某些平台上的未定义行为(即8051)。但是,我甚至从未收到过关于编译器的警告。 是否将指针传递给具有(const My_Struct *)
的函数时没有对指针进行类型转换可能导致未定义的行为?
我用指向const
的指针声明上述函数的原因是因为我希望能够同时处理指向const和指针的指针。 在上述情况下不进行类型转换是不好的编码习惯?
感谢您的帮助!
答案 0 :(得分:4)
这绝对没问题;编译器执行从My_Struct *
到const My_Struct *
的隐式转换。 C99规范的§6.3.2.3说:
对于任何限定符 q ,指向非 q - 限定类型的指针可能会转换为指向 q - 限定的指针版型;存储在原始指针和转换指针中的值应相等。
此外,即使您使用两个不一致的声明声明该函数,例如一个文件看到它声明如下:
void myFunction(My_Struct * p_my_struct);
即使它实际上是这样定义的:
void myFunction(const My_Struct * p_my_struct) { ... }
即使编译器允许这样做,即使编译器不知道执行隐式转换,因为My_Struct *
和const My_Struct *
具有相同的表示(因此转换是无操作的,无论如何)。
(感谢Christoph和awoodland的评论澄清后一种情况。在此答案的先前版本中,我错误地声称将成为未定义的行为。)
编辑添加:反向 - 使用带有指针到非const参数的声明定义一个函数,但使用带有指针到const参数的声明来调用它 - 是出于同样的原因也允许;但是试图实际修改数据很可能导致未定义的行为,具体取决于它来自何处。 (例如,一个char *
可以初始化一个字符串常量,但尝试修改该常量中的数据是未定义的行为。)
答案 1 :(得分:2)
在我认为不好的做法之类的情况下输入或关闭事物的类型 - 将非const指针传递给期望const的函数通常没有错。
例外情况是,如果有某些原因导致数据在执行过程中发生了某种变化(例如,另一个线程触及指向的数据) - 那么您可能会遇到问题,但这不是类型转换会阻止的问题。在这种情况下,您需要使您的逻辑线程安全。
不要忘记编译器不能使用const关键字来保证const,尽管它可以用于检测您认为数据不应该更改的问题,但编译器希望您想要更改它...它更适合你的文档工具。
答案 2 :(得分:1)
这对我有用,我不认为const指针参数会产生未定义的行为,编译器在调用函数之前会进行隐式转换:
typedef struct
{
unsigned char x;
unsigned short y;
unsigned char[NUM_DEFINED_ELSEWHERE];
} My_Struct;
static My_Struct my_useful_struct; // Variables initialized elsewhere in code.
void myFunction(const My_Struct * p_my_struct)
{
/* Performs various read-only actions utilizing p_my_struct. */
}
void myOtherFunction(void)
{
static My_Struct * p_struct = &my_useful_struct;
myFunction(p_struct);
}
答案 3 :(得分:1)
首先我假设&
来电中的myFunction(&p_struct)
是一个拼写错误,你真正的意思是myFunction(p_struct)
。
static My_Struct * p_struct = &my_useful_struct;
myFunction(p_struct);
当您传递p_struct
时,绝对没有理由在函数调用中强制转换p_struct
指针。在参数指向T
的函数中,将指针传递给const T
非常有效。
在C标准中,这由赋值运算符(C99,6.5.16.1p1)的约束决定。在使用原型声明的函数的函数调用中,参数的转换就像分配给相应参数的类型一样(C99,6.5.2.2p7)。