Строгое правило наложения имен - пункт 6.5 / 7 Стандарта . В основном это говорит о том, что вы можете получить доступ к объекту только через lvalue совместимого типа, возможно, с дополнительными квалификаторами; соответствующий тип со знаком / без знака; массив, структура или тип объединения с одним из этих элементов или тип символа. Полученная вами диагностика говорит о том, что ваш код нарушает это правило, и повторяется несколько раз.
У вас очень рано возникают проблемы с:
T1 = (struct text *)data;
Это преобразование разрешено, хотя результирующий указатель не гарантированно будет правильно выровнен, но вы не сможете многое сделать с T1
, не нарушая строгое правило алиасинга. В частности, если вы разыменовываете его с помощью *
или ->
- что на самом деле является следующим, что вы делаете - тогда вы получаете доступ к массиву char
, как если бы это был struct text
. Это недопустимо, хотя обратное было бы другой историей.
Преобразование T1
в char *
и доступ к указанному массиву через этот указатель, как вы делаете позже, - вот некоторые из немногих вещей, которые может сделать с ним.
gettextexpr()
одинаково (обе версии). Он выполняет преобразование того же типа, что описано выше, и разыменовывает преобразованный указатель при обращении к p->count
. Получающееся поведение нарушает строгое правило алиасинга и поэтому не определено. Однако на самом деле GCC жалуется во втором случае на доступ к *T1
, как если бы это был char *
, тогда как на самом деле это struct text *
- другое, отдельное, строгое нарушение псевдонимов.
Итак, в ответ на ваши конкретные вопросы:
- Был ли код вызывающим по значению в первом случае?
C имеет только передачи по значению, так что да. В первом случае вы передаете два указателя char
по значению, которые затем можно использовать для изменения данных char
вызывающего. Во втором случае вы передаете два char *
указателя по значению, которые вы можете и использовать для изменения переменных char *
вызывающего.
- Разрешено ли использование (char **) для приведения при соблюдении строгих правил наложения имен?
Нет, абсолютно нет. Приведение к char *
(не char **
) может позволить вам получить доступ к представлению объекта через результирующий указатель, потому что разыменование char *
создает lvalue символьного типа, но нет типа, который может обычно преобразуется из без последствий для строгого наложения.
- Что мне не хватает, чтобы устранить это предупреждение?
Вам не хватает того, что вы пытаетесь сделать принципиально запрещено. C не разрешает доступ к массиву char
, как если бы это был период struct text
. Тем не менее, компиляторы могут принимать код, который делает это, но его поведение не определено.
Устраните предупреждение, отказавшись от подхода «структура-структура», который в любом случае обеспечивает только притирание синтаксического сахара. На самом деле проще и понятнее избавиться от кастинга и написать:
count = ((*T1)[0] - '0') * 10 + ((*T1)[1] - '0');
Возможно, еще яснее избавиться от использования заклинаний sscanf
:
sscanf(*T1, "%2d", &count);
Обратите внимание, что даже если бы это было разрешено, ваш конкретный шаблон доступа, кажется, делает предположения о расположении элементов структуры, которые не оправданы языком. Реализации могут использовать произвольные отступы между членами и после последнего члена, и ваш код не может это учитывать.