Изменит ли f (mystruct * a) на f (const mystruct * a) API / ABI в C? - PullRequest
7 голосов
/ 22 февраля 2011
1: void f(mystruct *a)
2: void f(const mystruct *a)

Изменяет ли сигнатура функции с 1-> 2 разрыв API / ABI в C?
Как насчет изменения 2-> 1?

Ответы [ 5 ]

5 голосов
/ 23 февраля 2011

Из стандарта C99 6.2.5 / 26 «Типы»:

указатели на квалифицированные или неквалифицированные версии совместимых типов должны иметь одинаковые требования к представлению и выравниванию.

Таким образом, ABI / API не должен изменяться от 1 до 2. (API не изменяется, потому что указатель на неконстантный тип может быть преобразован в указатель на константную версию типа -6.3.2.3/2 «Преобразования - указатели»).

Однако если перейти от 2 к 1, то API изменится, поскольку указатель на объект const не может быть неявно преобразован в указатель на неконстантный объектСледующий код будет компилироваться в версии 2, но не будет компилироваться в версии 1:

static const mystruct foo;

f(&foo);
4 голосов
/ 23 февраля 2011

Иное, чем указано в двух предыдущих ответах, начиная с 1-> 2, может нарушать или не нарушать API. Это зависит от базового типа mystruct. API сломался бы, если бы то, что не указано в названии, mystruct было бы typedef для типа массива.

typedef struct toto mystruct[1];

Для такого зверя

mystruct A;
f(&A);

вызов f будет действительным до изменения API, но впоследствии недействительным.

3 голосов
/ 22 февраля 2011

Это зависит от того, что вы подразумеваете под API.Во время компиляции T * всегда может быть неявно преобразовано в const T * ( Примечание: кроме исключения, на которое указал Дженс Гастедт в своем ответе! ).Обратное неверно;const T * не будет неявно преобразован в T *, поэтому всегда требуется приведение во избежание ошибки компилятора.Таким образом, если вы измените объявление функции интерфейса с const на не-const, то ваш клиентский код не скомпилируется.(Вы можете обойти это, просто отбрасывая const -несс во всех вызовах, но этого следует избегать, за исключением случаев, когда это абсолютно неизбежно, поскольку поведение не определено, а это означает, что вы нарушили контракт собственного интерфейса).

На уровне битов (то есть ABI) не будет никакой разницы между представлениями ваших указателей или объектов.Однако это не означает, что компилятор не будет делать оптимизацию / допущения, основываясь на том, что что-то помечено const, когда сгенерированный машинный код обрабатывает эти представления;если вы отбросите const -несс, эти предположения могут больше не выполняться, и код будет нарушен.

2 голосов
/ 22 февраля 2011

Что касается ABI, то нет, const влияет только на ошибки на этапе компиляции. Скомпилированные объектные файлы не должны иметь остатков спецификаторов const.

0 голосов
/ 02 сентября 2011
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): Этот пример показывает ошибку компилятора, чем изменение параметра на неконстантный:

библиотека 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 ++.Таким образом, вы сломаете приложения на основе C, скомпилированные с опцией -Werror, и приложения на C ++, скомпилированные с помощью G ++.

...