2015-07-23 3 views
2

Пожалуйста, обратите внимание на следующий фрагмент кода,Понимание маркера склеивание

#include<stdio.h> 
#define AB "HELLO" 
#define A "WORLD" 
#define MAC1 A##B 
void main(void) 
{ 
    printf(MAC1"\n"); 
} 

При компиляции и выполняется печать ПРИВЕТ. Пожалуйста, помогите понять, почему ## игнорируются между A и B.

Кроме того, когда следующий код компилируется, дает следующее сообщение об ошибке,

#include<stdio.h> 
#define AB "HELLO" 
#define A "WORLD" 
#define MAC2 A#B 
void main(void) 
{ 
    printf(MAC2"\n"); 
} 

21.c: In function âmainâ:
21.c:11:2: error: stray â#â in program
21.c:11:9: error: expected â)â before string constant

Почему такое поведение?

+0

## является лексема/символ конкатенации, # принимает операнд и превращает его в строку (например, #define макинтош (х) #x, если я прохожу макинтош (MYVAR) I получите «myVar» в своем месте. Для литеральной конкатенации строк просто поместите их рядом с eachother (например, «Hello» «World» или в #define MAC1 AB A) – ydobonebi

ответ

2

Маркер ## предварительной обработки используется для маркеров оклейки.

Эффект A##B, внутри определения макроса, заключается в создании токена AB. Таким образом, printf(MAC1"\n") - это то же самое, что и printf(AB"\n").

Токен не «проигнорирован», он выполняет свою работу.


В вашем втором примере A#B просто буквально означает A#B. # имеет особый смысл в функционально-подобном макросе.Так что ваш код расширяется:

printf(A#B"\n"); 

который является ошибкой, поскольку # не является частью синтаксиса C, вне препроцессора.

1

Токены # и ## являются специальными в расширениях макросов. '##' - оператор точечного вставки. Он принимает 2 символа в макросе и связывает их в один символ. Это полезно для создания специализированных имен.

#define LINE_COUNTER static int line## __LINE__ =0; line ## __LINE__ ++; 

Это создает переменную, которая получает приращение при выполнении строки. Он может использоваться несколько раз в той же функции, поскольку он имеет уникальное имя, основанное на номере строки. (статический int line_17 = 0; line_17 ++;)

Символ '#' является оператором стробирования. Он превращает то, что следует за ним в строку.

#define assert(x) if(! x) { fprintf(stderr, "Assertion failed %s\n", #x); exit( 1) } 
+0

выше ответ недостаточно ясен, можете ли вы его привести чистый формат? – Madara

0

Символ ## объединяет символы. Другими словами, A ## B означает AB, который отсутствует. Если вы хотите сделать что-то подобное сделать имя переменной от 2-х имен переменных, вы могли бы использовать, что таким образом:

#define newVar(x,y) x##y 

int main() 
{ 
    int newVar(my,Var); // int myVar; 
    newVar(f,printf)(stdout,"Hello World"); // fprintf(stdout,"Hello World"); 
} 

# принимает имя, и превращает его в строку. например

#define VARSTR(x) #x 

int main() 
{ 
    printf(VARSTR(myVar)); 
} 

печатает «MYVAR» в строке (даже если MYVAR не является переменной основной, он находится в пределах макро замены)

#define "HELLO" "WORLD" 

Объединяем строковых литералов они просто должны быть расположенных рядом друг с другом, без каких-либо других действительных токенов между ними. Так что результаты в «HELLOWORLD» Обратите внимание, что пробел между литералами игнорируется и не нужен. Я использовал это, чтобы прояснить это.

Это заменит АА и ВВ, как это:

#include<stdio.h> 
#define AA "HELLO" 
#define BB "WORLD" 
#define MAC1 AA BB 
void main(void) 
{ 
    printf(MAC1"\n"); // printf("HELLO" "WORLD""\n"); 
    // same as printf("HELLOWORLD\n"); 
} 
+0

Это приведет к ошибке компилятора. '#define MAC1 A ## B' создаст символ' AB', который неизвестен компилятору. – muXXmit2X

+0

@ muXXmit2X ah, извините, вы правы. Исправлено – ydobonebi

+0

" исправленная "версия - это правильный код, но не тот, о котором спрашивает ОП. У него нет опечатки, он хочет понять, что такое поведение его код. –

0

Как указывалось другим, оператор ## используется для создания новых токенов. #define MAC1 A##B создаст макрос AB, который был определен так, чтобы содержать строку HELLO. Именно по этой причине printf(MAC1"\n") печатает «HELLO». Если вы хотите Concat строки, представленные AB и A вы можете определить MAC1 следующим образом:

#define MAC1 AB A 

Ваш препроцессор будет первым заменить AB B с "HELLO""WORLD так MAC1 будет выглядеть, что

#define MAC1 "HELLO""WORLD" 

затем его заменит MAC1 везде, где он появится. Так что ваш Printf заявление будет

printf("HELLO""WORLD""\n"); // --> HELLOWORLD 
+0

Фактически, он заменил бы AB A «HELLO» «WORLD» в макросе в первую очередь. Затем MAC1 будет заменен на «HELLO» «WORLD» (а не AB A первым). Если я ошибаюсь, он читается сверху вниз и заменяется в этом порядке, поскольку AB и A определены сначала, они заменяются в MAC1, Затем printf (MAC1 ...) получает свою замену позже. Не то чтобы это важно, все происходит так же, как и в конце. – ydobonebi

+0

@QuinnRoundy Ты прав. Я починил это. Я также испортил порядок замещения ... – muXXmit2X

Смежные вопросы