LINUX.ORG.RU

clang: error: disabled expansion of recursive macro

 ,


0

1

Привет,

в свободное время учу c, зачастую возникают непонятные моменты.

Например - здесь https://gist.github.com/lx93uv/8aee16ad67eace5383a947275cfcc533 простой пример, когда gcc 6.3 отображает меньше warning-ов, чем clang (3.8). В частности, gcc не показал ни одного.

Есть один интересный:

app.c:43:24: error: disabled expansion of recursive macro [-Werror,-Wdisabled-macro-expansion]
      ch = (char) getc(stdin);
                       ^
/usr/include/stdio.h:174:15: note: expanded from macro 'stdin'
#define stdin stdin

Его можно как-нибудь пофиксить?


Его можно как-нибудь пофиксить?

Выключив это предупреждение или воспользовавшись getchar(). Это бок предупреждения, которое ругается на нормальный код. Ещё можно макрос подавить, окружив getc скобками, но это лишнее.

И -Weverything в clang не эквивалентно -Wall -Wextra в GCC, так как ряд флагов этим не включается (но не знаю, сколько ещё предупреждений они добавили бы).

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от xaizek

А что вообще означает «error: disabled expansion of recursive macro»? Использование макроса в качестве аргумента функции?

Из /usr/include/stdio.h:

/* Define ISO C stdio on top of C++ iostreams.  */

...

/* C89/C99 say they're macros.  Make them happy.  */
#define stdin stdin
#define stdout stdout
#define stderr stderr
Т.е. получается, что c-шное stdio - обёртка над c++?

И вообще, рекурсивные макросы - это нормально?

***

Ещё можно макрос подавить, окружив getc скобками, но это лишнее.

Вот так?

ch = (char) (getc(stdin))
Не работает.

***

Так тоже не работает (собирается, но не выводит при нахождении патерна)

ch = (char) getchar();

lx93uv
() автор топика
Ответ на: комментарий от lx93uv

Я перепроверил, твои/ваши советы правильны, всё работает.

Жаль, нельзя редактировать комменты.

И, почему вариант

ch = (char) (getc(stdin))
валиден?

lx93uv
() автор топика
Ответ на: комментарий от lx93uv

Я думал он ругается на то, что и getc и stdin являются макросами, но тогда было бы nested. Это плохое предупреждение просто.

Имелось в виду:

ch = (char) (getc)(stdin)
Но это работает только для function-like макросов, т.е. с stdin не пройдёт.

И вообще, рекурсивные макросы - это нормально?

Да, они просто не раскрываются внутри себя, всё так и должно быть по стандарту. Это предупреждение в стиле «что-то могло пойти не так как задумывалось», а не о том, что здесь что-то не так.

ch = (char) getchar();

ch должен быть int и каст тут не нужен, иначе проверка на EOF не сработает.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

ch должен быть int и каст тут не нужен, иначе проверка на EOF не сработает.

/* так работает */
char *getln()
{
    char *line = NULL, *tmp = NULL;
    size_t size = 0, index = 0;
    char ch = EOF;

    while (ch) {
        ch = (char) (getc(stdin));

        /* Check if we need to stop. */
        if (ch == EOF || ch == '\n')
            ch = 0;

        /* Check if we need to expand. */
        if (size <= index) {
            size += 1;
            tmp = realloc(line, size);
            if (!tmp) {
                free(line);
                line = NULL;
                break;
            }
            line = tmp;
        }

        /* Actually store the thing. */
        line[index++] = ch;
    }

    return line;
}
/* здесь предупреждение */
char *getln()
{
    char *line = NULL, *tmp = NULL;
    size_t size = 0, index = 0;
    int ch = EOF;

    while (ch) {
        ch = (getc(stdin));

        /* Check if we need to stop. */
        if (ch == EOF || ch == '\n')
            ch = 0;

        /* Check if we need to expand. */
        if (size <= index) {
            size += 1;
            tmp = realloc(line, size);
            if (!tmp) {
                free(line);
                line = NULL;
                break;
            }
            line = tmp;
        }

        /* Actually store the thing. */
        line[index++] = ch;
    }

    return line;
}


/*
app.c:68:25: error: implicit conversion loses integer precision: 'int' to 'char'
      [-Werror,-Wconversion]
        line[index++] = ch;
                      ~ ^~
1 error generated.
Makefile:18: recipe for target 'clang' failed
make: *** [clang] Error 1

*/
lx93uv
() автор топика
Ответ на: комментарий от lx93uv

так работает

Поставь символ с кодом 255 в начало файла. Потом внимательно почитай стандарт и подумай, где ты неправ.

kawaii_neko ★★★★
()
Ответ на: комментарий от lx93uv

/* так работает */

Оно поломается, если во вводе будет символ с кодом 255, а на архитектурах, где char по умолчанию беззнаковый, EOF вообще не будет определён. getc()/getchar() возвращают int не просто так.

/* здесь предупреждение */

Его надо исправлять, добавив каст именно в то место:

line[index++] = (char)ch;

А

    int ch = EOF;

    while (ch) {
должно быть
    int ch = 0;

    while (ch != EOF) {

    // и там ниже ch = EOF сделать
Символ с кодом 0 тоже может быть во вводе.

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.