将指针传递给具有const指针形式参数的函数时未定义的行为?

时间:2012-02-25 17:41:35

标签: c embedded const-correctness

我一直在研究一些类似于以下内容的代码:

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和指针的指针。 在上述情况下不进行类型转换是不好的编码习惯?

感谢您的帮助!

4 个答案:

答案 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)。