Как #define переносит имя функции в c?

Проработав более 10 лет, сегодня мне на глаза попался код, я не могу понять, как имя функции, определенное внутри функции, печатается в выводе/журнале, не будучи переданным в качестве аргумента в макросе или определяемым как глобальная переменная. Помогите, пожалуйста, разобраться во внутреннем. Пожалуйста, смотрите скриншот для справки.

/*...*/
#include <stdio.h>
#define x printf("%s", f);
int main() {
    char *f = "MAIN";
    printf("Hello World");
    x;
    
    return 0;
}

Вывод:

Hello WorldMAIN

Пожалуйста, не размещайте изображения кода. Пожалуйста, отправьте код в виде текста.

KamilCuk 01.11.2022 01:27

1) Пожалуйста, НЕ размещайте изображения; скопируйте/вставьте свой код как ТЕКСТ. 2) почитайте о макросах C: #define. Все, что он делает, это «заменяет текст». 3) В частности, везде, где препроцессор C увидит «x», он заменит текст printf("%s", f);, прежде чем передать его компилятору. 4) Этот конкретный макрос ПЛОХОЙ... по многим-многим причинам. Пожалуйста, рассмотрите возможность избавиться от него!

paulsm4 01.11.2022 01:29

большой или маленький, это не имеет значения. У вас более 11 тысяч репутации, и вы все еще делаете эту глупость? Почему нельзя загружать изображения кода/данных/ошибок?

phuclv 01.11.2022 01:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
4
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Макросы препроцессора C просто выполняют замену текста. У них нет семантической осведомленности о вашей программе.

Этот:

#include <stdio.h>
#define x printf("%s", f);

int main()
{ 
    char* f = "MAIN";  
    printf ("Hello World");
    x;
    return 0;
}

Становится:

#include <stdio.h>

int main()
{ 
    char* f = "MAIN";  
    printf ("Hello World");
    printf("%s", f);;
    return 0;
}

Обратите внимание, что если при использовании этого макроса не объявлено f, вы увидите ошибку компилятора. Если f объявлен, но не является char *, вы должны увидеть предупреждения компилятора.

Некоторые лучшие практики макросов препроцессора включают (но не ограничиваются) использование имен с заглавными буквами, поскольку x по соглашению выглядит как имя переменной или функции; и будьте осторожны с тем, какие синтаксически значимые символы (в данном случае ;) вы включаете в свой текст макроса.

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

Спасибо за отличное объяснение и за указание на некоторые проблемы в примере макроса OP. Макросы могут быть чрезвычайно полезными. Но макрос ОП — отличный пример того, как НЕ использовать макросы. Это программный ужас.

paulsm4 02.11.2022 04:16

Макросы препроцессора — это просто замена текста. Все операторы #include заменяются содержимым указанных файлов. Все вхождения символов #define'd заменяются их указанным текстом. Все комментарии опущены. Так далее...

Итак, в вашем примере:

/*...*/
#include <stdio.h>
#define x printf("%s", f);
int main() {
    char *f = "MAIN";
    printf("Hello World");
    x;
    
    return 0;
}

Препроцессор заменяет все экземпляры x текстом printf("%s", f); перед тем, как обработанный код будет отправлен компилятору. Итак, вот код, который на самом деле видит компилятор:

// contents of <stdio.h> here...

int main() {
    char *f = "MAIN";
    printf("Hello World");
    printf("%s", f);;
    
    return 0;
}

Другие вопросы по теме