1: void f(mystruct *a)
2: void f(const mystruct *a)
将函数签名从 1->2 更改是否会破坏 C 中的 API/ABI?
改变 2->1 怎么样?
1: void f(mystruct *a)
2: void f(const mystruct *a)
将函数签名从 1->2 更改是否会破坏 C 中的 API/ABI?
改变 2->1 怎么样?
从 C99 标准 6.2.5/26“类型”:
指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。
因此,从 1 到 2 不应该影响 ABI/API。(API 不会改变,因为指向非 const 限定类型的指针可能会转换为指向该类型的 const 限定版本的指针 - 6.3 .2.3/2“转换 - 指针”)。
但是,如果从 2 变为 1,那么 API 会发生变化,因为指向 const 对象的指针不能隐式转换为指向非 const 对象的指针。以下代码将在版本 2 下编译,但不会在版本 1 下编译:
static const mystruct foo;
f(&foo);
除了前面两个答案中所述的 1->2 可能会或可能不会破坏 API。这取决于基本类型mystruct
。如果不是名称所指的数组类型,则 API 将mystruct
中断typedef
。
typedef struct toto mystruct[1];
对于这样的野兽
mystruct A;
f(&A);
调用f
在 API 更改之前有效,但之后无效。
这取决于你所说的 API 是什么意思。在编译时, aT *
可能总是被隐式转换为 a const T *
(注意:除了 Jens Gustedt 在他的回答中指出的例外!)。反之则不成立;aconst T *
不会被隐式转换为 a T *
,因此始终需要强制转换以避免编译器错误。因此,如果您将接口函数的声明从更改const
为 non- const
,那么您的客户端代码将不会编译。(你可以简单地通过在所有调用中抛弃const
-ness 来解决这个问题,但除非绝对不可避免,否则应该避免这样做,因为行为是未定义的,这意味着你已经违反了自己接口的合同)。
在位级别(即 ABI),指针或对象的表示之间没有区别。但是,这并不是说编译器不会根据const
生成的机器代码处理这些表示时标记的内容进行优化/假设;如果你抛弃const
-ness,这些假设可能不再成立,代码就会中断。
就 ABI 而言,不,const
唯一会影响编译阶段的错误。编译的目标文件应该没有 const 说明符的残余。
OLD: void f(mystruct *a)
NEW: void f(const mystruct *a)
ABI:如果a
是一个out参数,那么旧的应用程序可能会被破坏。
API:似乎是兼容的。
OLD: void f(const mystruct *a)
NEW: void f(mystruct *a)
ABI:该函数f
可能会尝试更改一个参数值,该参数值应该被旧应用程序更改。
API:编译器错误。
编辑(1):这是一个显示编译器错误的示例,而不是将参数更改为非常量:
库头文件.h:
struct mystruct {
int f;
};
void f(struct mystruct *a);
应用:
int main()
{
const struct mystruct x = {1};
f(&x);
return 0;
}
编译器错误(gcc -Werror app.c
):
error: passing argument 1 of ‘f’ discards qualifiers from pointer target type
note: expected ‘struct mystruct *’ but argument is of type ‘const struct mystruct *’
默认情况下,这在 C 中确实是一个警告,但在 C++ 中却是一个错误。因此,您将破坏使用-Werror
选项编译的基于 C 的应用程序和使用 G++ 编译的基于 C++ 的应用程序。