Исправление предупреждений g cc с помощью макроса _Generi c и составных литералов - PullRequest
1 голос
/ 08 апреля 2020

У меня есть структура с объединением и перечислением такого рода. Я создал макрос, который выводит составной литерал структуры, который устанавливает тип и данные объединения в соответствии с типом, передаваемым макросу: _Generi c.

Пример кода:

#include <stdio.h>

struct mystruct {
    enum { K_NUM, K_STR } kind;
    union { int num; char * str; };
};

#define MYSTRUCT(X) _Generic((X), \
    int: (struct mystruct){K_NUM, .num=X}, \
    char *: (struct mystruct){K_STR, .str=X} \
)

void print_mystruct(struct mystruct s) {
    switch (s.kind) {
    case K_NUM: printf("mystruct (num): %d\n", s.num); break;
    case K_STR: printf("mystruct (str): %s\n", s.str); break;
    }
}

int main() {
    print_mystruct(MYSTRUCT(2));
    print_mystruct(MYSTRUCT("test"));
}

Он компилируется с g cc, а затем запускается правильно:

mystruct (num): 2
mystruct (str): test

Но я получаю все эти предупреждения компиляции:

c.c: In function 'main':
c.c:21:26: warning: initialization of 'char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   21 |  print_mystruct(MYSTRUCT(2));
      |                          ^
c.c:10:40: note: in definition of macro 'MYSTRUCT'
   10 |  char *: (struct mystruct){K_STR, .str=X} \
      |                                        ^
c.c:21:26: note: (near initialization for '(anonymous).<anonymous>.str')
   21 |  print_mystruct(MYSTRUCT(2));
      |                          ^
c.c:10:40: note: in definition of macro 'MYSTRUCT'
   10 |  char *: (struct mystruct){K_STR, .str=X} \
      |                                        ^
c.c:22:26: warning: initialization of 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
   22 |  print_mystruct(MYSTRUCT("test"));
      |                          ^~~~~~
c.c:9:37: note: in definition of macro 'MYSTRUCT'
    9 |  int: (struct mystruct){K_NUM, .num=X}, \
      |                                     ^
c.c:22:26: note: (near initialization for '(anonymous).<anonymous>.num')
   22 |  print_mystruct(MYSTRUCT("test"));
      |                          ^~~~~~
c.c:9:37: note: in definition of macro 'MYSTRUCT'
    9 |  int: (struct mystruct){K_NUM, .num=X}, \
      |                                     ^

I пробовал приводить составные литералы примерно так:

int: (struct mystruct){K_NUM, .num=(int)X}, \
char *: (struct mystruct){K_STR, .str=(char *)X} \

Но я получаю разные предупреждения:

c.c: In function 'main':
c.c:9:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    9 |  int: (struct mystruct){K_NUM, .num=(int)X}, \
      |                                     ^
c.c:22:17: note: in expansion of macro 'MYSTRUCT'
   22 |  print_mystruct(MYSTRUCT("test"));
      |                 ^~~~~~~~

1 Ответ

2 голосов
/ 08 апреля 2020

Это происходит потому, что каждый раз, когда вы вызываете макрос, все случаи, когда найден параметр макроса X, расширяются. Поэтому, когда вы передаете 2, вы получаете

_Generic(2, int: (struct mystruct){K_NUM, .num=2}, char *: (struct mystruct){K_STR, .str=2}

И даже если регистр char* не выполнен, он все равно скомпилирован, и присвоение целого числа строке .str=2 недопустимо C.

Подумайте о совершенно ином подходе. Например, оставьте аргумент макроса вне списка _Generi c. И вам даже нужно перечисление, так как типы известны во время компиляции?

#include <stdio.h>

void print_int (int x) { printf("%d\n", x); }
void print_str (const char* x) { puts(x); }

#define print(x) _Generic((x), \
  int:    print_int,           \
  char*:  print_str ) (x)

int main(void) 
{
  print(2);
  print("test");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...