совместимость тега структуры в c - PullRequest
1 голос
/ 18 апреля 2020

Я прочитал, что, начиная с C99, два полных struct, определенных в разных файлах, должны иметь одинаковый тег для совместимости.

Поэтому я написал следующий код:

file1. c:

/* file1.c */
#include <stdio.h>

typedef struct tag1 { int foo; } type1;
type1 a; 
void func(void);

int main() {
    printf("a.foo : %d\n", a.foo); 
    func();
    printf("a.foo : %d\n", a.foo); 
    return 0;
}

file2. c:

/* file2.c */
typedef struct tag2 { int foo; } type2; 
type2 a;
void func(void) {
    a.foo = 100;
}

и ожидается, что два a будут считаются разными и поэтому оба printf должны печатать a.foo : 0, но вывод:

a.foo : 0
a.foo : 100

Почему это так?

1 Ответ

3 голосов
/ 18 апреля 2020

Что касается проблемы типа, то правила в стандартном C сводятся к следующему:

  • Если , вы объявляете a, используя один и тот же тег структуры в обоих файлы, , затем ваша программа будет работать (в этом отношении).

Обратите внимание, что стандарт C не говорит о том, что произойдет, если часть «Если» будет нарушена. В этом случае стандарт C не говорит, что ваша программа будет работать, он не говорит, что ваша программа не будет работать, он не говорит, что будет сообщение об ошибке, он не говорит, что сообщения об ошибке не будет. Он просто ничего не говорит.

В программе есть еще одна проблема: type1 a; и type2 a; являются предварительными определениями из a, которые, согласно стандарту C, разрешить определениям. Тогда a определяется в нескольких единицах перевода, что нарушает C 2018 6.9 5:

… Если идентификатор, объявленный с внешней связью, используется в выражении (отличном от части операнда) оператора sizeof или _Alignof, результатом которого является целочисленная константа), где-то во всей программе должно быть ровно одно внешнее определение для идентификатора; в противном случае их должно быть не более одного.

Однако давайте предположим, что ваша реализация C определяет их для разрешения их в один объект, как это обычно делают реализации C в Unix , Мы рассмотрим только проблему типа.

Затем вы получаете доступ к объекту a с двумя несовместимыми типами. Это нарушает C 2018 6.5 7:

Доступ к сохраненному значению объекта должен осуществляться только через выражение lvalue одного из следующих типов:…

где в этом случае ни один из перечисленных типов не выполняется. C 2018 4 2 сообщает нам, каковы последствия этого нарушения:

Если требование «должен» или «не будет» появляется за пределами ограничения или ограничения времени выполнения, то поведение не определено…

И C 2018 3.4.3 говорит нам, что это означает:

поведение, при использовании непереносимой или ошибочной программной конструкции или ошибочной конструкции данные, к которым данный документ не предъявляет требований

То есть: из-за нарушения типа стандарт C не предъявляет требований к реализации C. Стандарт разрешает вашей реализации (компилятор, компоновщик, библиотека, операционная система, аппаратное обеспечение и все остальное, что необходимо для сборки и запуска C программ), чтобы принять вашу программу, отклонить вашу программу, запустить вашу программу, отказаться от запуска вашей программы, предупреждаю, не предупреждаю, пусть ваша программа плохо себя ведет и многое другое. Стандарт просто ничего не говорит о том, что должно произойти.

...