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

将指针传递给具有形式参数pointer to const的函数时的未定义行为?,c,embedded,const-correctness,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

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

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的指针和指针在上述情况下不进行打字是不是很糟糕的编码实践?


谢谢你的帮助

这对我很有效,我认为const pointer参数不会产生未定义的行为,编译器在调用函数之前会进行隐式转换:

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);
}

型铸造稳定或关闭的东西是我认为不好的做法-一般不存在任何错误,通过一个非const指针到一个函数期待一个const。 例外情况是,如果由于某种原因,数据可以在执行过程中部分更改(例如,另一个线程接触指向的数据),那么您可能会遇到问题,但这不是类型转换所能防止的问题。在这种情况下,您需要使您的逻辑线程安全


不要忘记,编译器也不能使用const关键字来保证constness,尽管它可以用于检测您认为数据不应更改的问题,但编译器希望您更改它。。。它对您来说更像是一个文档工具。

这绝对不错;编译器执行从
My\u Struct*
const My\u Struct*
的隐式转换。C99规范的§6.3.2.3规定:

对于任何限定符q,指向非q限定类型的指针可以转换为指向该类型的q限定版本的指针;原始指针和转换指针中存储的值应相等

此外,即使使用两个不一致的声明声明函数,一个文件也会看到它是这样声明的:

void myFunction(My_Struct * p_my_struct);
void myFunction(const My_Struct * p_my_struct) { ... }
尽管它实际上是这样定义的:

void myFunction(My_Struct * p_my_struct);
void myFunction(const My_Struct * p_my_struct) { ... }
即使这是规范所允许的,即使编译器不知道执行隐式转换,因为
My_Struct*
const My_Struct*
具有相同的表示形式(因此转换无论如何都是无操作的)

(感谢Christoph和awoodland澄清后一种情况的评论。在之前的回答中,我错误地宣称这是未定义的行为。)



编辑以添加:出于同样的原因,也允许反向定义函数,即使用指向非常量参数的指针的声明定义函数,但使用指向常量参数的指针的声明调用函数;但试图实际修改数据很可能会导致未定义的行为,这取决于数据的来源。(例如,
char*
可以通过初始化字符串常量来初始化,但是试图修改该常量中的数据是未定义的行为。)

首先,我假设
myFunction(&p_struct)
调用中的
是一个输入错误,您真正的意思是
myFunction(p_struct)

当您传递
p_struct
时,绝对没有理由在函数调用中强制转换
p_struct
指针。在参数为指针指向
const T
的函数中,传递指向
T
的指针非常有效


在C标准中,这是由赋值运算符(C99,6.5.16.1p1)的约束决定的。在使用原型声明的函数的函数调用中,参数被转换为相应参数的类型(C99,6.5.2.2p7)。

(学究注:如果它是未定义的行为,那么它在所有平台上都是未定义的,碰巧你运气不好,在某些平台上“起作用”)您的代码不应编译:
static My\u Struct p\u Struct=&My\u usupulable\u Struct是非法的。只有指针才能接收某物的地址…我想你把
myOtherFunction()
搞砸了-你可能希望
p\u struct
成为一个指针,并从下面的调用中删除
&
…正如@Christoph所说,这不应该编译每个指针类型
t*
都可以隐式转换为
t const*
,因此不需要强制转换(事实上,这是完全合乎逻辑的)。
const
-限定指向类型绝对不能保证指向对象的可变性-这纯粹是语法上的,因为添加限定符是一种隐式转换,而删除限定符并不是…[附录],除非与
restrict
结合使用,但即使如此,也只有在对象实际被访问的情况下…实际上,
My_Struct*
const My_Struct*
要求内部相同(参见C99 6.2.5§27),但据我所知,你是对的,这两个声明在技术上是不兼容的,使用错误的声明是未定义的行为……那么,在调用函数之前进行强制转换的解决方案是什么呢?@Christoph:不,这应该是定义的行为,对吗?给出了错误的原型。@jupp0r:first--Christoph的意思是“使用正确的原型”。其次——如果原型不正确,显式转换将不起作用,因为如果将其显式转换为
const My_Struct*
,那么编译器将希望隐式转换它以与原型匹配!(这种隐含转换是非法的,更不用说是不可取的。)你给出的不允许的例子是明确允许的-§6.7.5.3/15明确规定:“在