将f(mystruct * a)更改为f(const mystruct * a)是否会破坏C中的API / ABI?

时间:2011-02-22 20:46:32

标签: c api const compatibility abi

1: void f(mystruct *a)
2: void f(const mystruct *a)

更改1> 2中的功能签名是否会破坏C中的API / ABI? 如何改变2-> 1?

5 个答案:

答案 0 :(得分:5)

来自C99标准6.2.5 / 26“类型”:

  

指向兼容类型的合格或非限定版本的指针应具有相同的表示和对齐要求。

因此ABI / API不应受影响从1到2.(API不会更改,因为指向非const限定类型的指针可能会转换为指向const限定版本的指针type - 6.3.2.3/2“Conversions - Pointers”)。

但是,如果从2变为1,则API会更改,因为指向const对象的指针不能隐式转换为指向非const对象的指针。以下代码将在版本2下编译,但不会在版本1下编译:

static const mystruct foo;

f(&foo);

答案 1 :(得分:4)

除了前面两个答案中所述的,从1> 2开始,可能会或可能不会破坏API。这取决于基类型mystruct。如果名称mystruct不是数组类型的typedef,则API会中断。

typedef struct toto mystruct[1];

对于这样的野兽

mystruct A;
f(&A);

f的调用在API更改之前有效,但之后无效。

答案 2 :(得分:3)

这取决于API的含义。在编译时,T *可能总是隐式转换为const T *注意:除了Jens Gustedt在他的回答中指出的例外情况!)。反之则不然; const T *不会隐式转换为T *,因此总是需要强制转换以避免编译错误。因此,如果将接口函数的声明从const更改为非const,则不会编译任何客户端代码。 (你可以简单地通过在所有调用中抛弃const来解决这个问题,但是除非绝对不可避免,否则应该避免这样做,因为行为是未定义的,这意味着你已经破坏了自己的接口契约)。

在位级(即ABI),指针或对象的表示之间没有区别。但是,这并不是说当生成的机器代码处理这些表示时,编译器不会根据标记为const的内容进行优化/假设;如果你抛弃const - ness,这些假设可能不再成立,代码将会中断。

答案 3 :(得分:2)

就ABI而言,不,const仅影响编译阶段的错误。编译的目标文件应该没有const说明符的残余。

答案 4 :(得分:0)

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:编译错误。

EDIT(1):这是一个显示编译器错误的示例,而不是将参数更改为非const:

library header.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 ++的应用程序。