Могу ли я преобразовать указатель структуры, чтобы он указывал на исходный анонимный элемент в C1x? Это вообще правильный вопрос?

Меня немного смущают анонимные структуры в C1x. Применяется ли правило, согласно которому указатель структуры, соответствующим образом преобразованный, указывает на свой первый элемент, к исходной анонимной структуре или просто к начальному члену исходной анонимной структуры? В частности, имеет ли смысл эта программа в C1x?

#include<stdio.h>

struct node {
    struct node *next;
};

/* Does C1x even allow this? Do I have to define struct node inside of inode?
 * Are anonymous struct members even allowed to have tags?
 */
struct inode {
    struct node;
    int data;
};

int main(void) {
    inode node1 = {NULL, 12};
    inode *ihead = &inode;
    node *head = (struct node *)ihead;

    /* These should work since struct inode's first member is a struct node. */
    printf("Are these equal? %c", head == &node1.next ? 'Y' : 'N');
    printf("Is next NULL? %c", head->next == NULL ? 'Y' : 'N');

    return 0;
}

Этот ответ предполагает, что я могу спросить о безымянных структурах вместо анонимных структур. Я совершенно неправильно понимаю природу анонимных структур?


person Michael Morris    schedule 03.08.2011    source источник
comment
Я постараюсь найти ответ, когда снова не буду звонить. Тем временем я добавил награду. Я не должен мириться с таким поведением, но посмотрите, сможете ли вы найти способ поднять этот вопрос или привлечь к нему внимание. Я хотел бы знать ответ.   -  person Chris Lutz    schedule 10.09.2011


Ответы (2)


/* Does C1x even allow this? Do I have to define struct node inside of inode?
 * Are anonymous struct members even allowed to have tags?
 */
struct inode {
    struct node;
    int data;
};

Во-первых, участник struct node не является анонимным. Он безымянный, но поскольку у него есть тег (node), он не соответствует определению "анонимный" в C1x.

Кроме того, это явно разрешено грамматикой C1x. Поскольку SO на самом деле не поддерживает нижние индексы, я пометил необязательные элементы квадратными скобками; Я также исключил грамматические правила, которые не нужны, чтобы увидеть, что это действительно:

type-specifier:
    struct-or-union-specifier
struct-or-union-specifier:
    struct-or-union [identifier] { struct-declaration-list }
struct-or-union:
    struct
    union
struct-declaration-list:
    struct-declaration
    struct-declaration-list struct-declaration
struct-declaration:
    specifier-qualifier-list [struct-declarator-list];
specifier-qualifier-list:
    type-specifier [specifier-qualifier-list]

Есть также 4 ограничения, которые должны быть выполнены, но ни одно из них не применяется к неименованным членам, так что это синтаксически правильно C.

Теперь, на ваш реальный вопрос. C1x говорит:

Указатель на объект структуры, соответствующим образом преобразованный, указывает на его начальный элемент (...) и наоборот.

Полная остановка. Никаких «если этот участник не безымянный». Таким образом, указатель на node1 также является указателем на безымянный начальный член, а также является указателем на node1.next. Однако здесь он начинает становиться немного мохнатым. Возможно, я просто пропустил пункт, но кажется, что C1x говорит только следующее:

Члены анонимной структуры или объединения считаются членами содержащей их структуры или объединения.

Я не могу найти формулировку, говорящую о том, что члены безымянной структуры считаются членами содержащей структуры. На самом деле может случиться так, что нет гарантированного способа доступа к next, кроме каламбура указателя. Я напишу некоторым людям в комитете, чтобы попросить разъяснений по этому вопросу.

Вы также можете столкнуться с проблемами при инициализации:

Безымянные члены объектов структуры имеют неопределенное значение даже после инициализации.

person Stephen Canon    schedule 10.09.2011
comment
+1 Я готов дать вам награду (через 11 часов, если не появится что-то получше) только за то, что вы написали комитет по стандартам. Пожалуйста, обновите это, если и когда они ответят. Мне очень любопытно, будет ли эта (чрезвычайно удобная) конструкция фичей или останется расширением. - person Chris Lutz; 11.09.2011
comment
Итак, комиссия приняла решение по этому поводу? - person Michael Morris; 31.07.2012

Попробуйте использовать node в качестве имени типа. Избегайте повторного объявления "struct node".

struct inode {
    node n;//node is a already a defined type name, n is the var name
    int data;
};
person robermorales    schedule 13.09.2011
comment
Я понимаю, что это поздно, но я считаю, что за вас проголосовали, потому что это вопрос C, а не вопрос C++. Для того, чтобы node был именем типа в C, он должен быть typedef'd. - person Michael Morris; 02.12.2012