Войти
ПрограммированиеФорумОбщее

[C++] Неопределённое поведение макроопределений

#0
21:04, 15 янв. 2013

Никак не пойму во что согласно стандарту должен разворачиваться макрос типа:

//test.cpp
#define F(A)A
int main()
{
  int value=F(1)1;
  return value;
}
если не вот в это, a?
cl.exe /P /EP /C /nologo /EHcs test.cpp
//test.i
int main()
{
  int value=11;
  return value;
}

Вот почему в gcc такой капризный?
http://ideone.com/QYlNFz

prog.cpp: In function 'int main()':
prog.cpp:4:17: error: expected ',' or ';' before numeric constant
сообщение об ошибке такое, как будто это мы пытаемся скомпилировать вот это:
int main()
{
  int value=1 1;
  return value;
}
http://ideone.com/eSUTwx

хм... ладно, а если вот так:

#define F(A)A
#define ToText0(A)#A
#define ToText(A)ToText0(A)
#include <stdio.h>
int main()
{
  const char str[]=ToText(int value=F(1)1;);
  printf("%s\n",str);
  return 0;
}
http://ideone.com/VTmqw0
output:
int value=11;
WTF???

ну, а если так:

#define F(A)A
#define ToText0(A)#A
#define ToText(A)ToText0(A)
#include <stdio.h>
int main()
{
  const char str[]=ToText(  int value        =        F(  1  )  1  ;  );
  printf("%s\n",str);
  return 0;
}
http://ideone.com/0J8TR5
output:
int value = 1 1 ;
>____<

ок, тогда так:

cl.exe /P /EP /C /nologo /EHcs test.cpp
...
int main()
{
  const char str[]="int value = 1 1 ;";
  printf("%s\n",str);
  return 0;
}

Неужели стандарт разрешает выкидывать пробелы в одних случаях и не запрещает добавлять невидимые пробелы в других случаях?

ps: стандарт вроде платный/закрытый поэтому я его не читал, но догадываюсь, что там про макросы нифига серьёзного не написано.


#1
21:24, 15 янв. 2013

http://stackoverflow.com/questions/841646/is-define-supposed-to-a… around-macros

Правильный вариант:

#define F(A, B) A ## B
int main()
{
  int value=F(1, 1);
  return value;
}

P.S. Исправил ссылку.

#2
21:59, 15 янв. 2013

Adler
> Неужели стандарт разрешает выкидывать пробелы в одних случаях и не запрещает
> добавлять невидимые пробелы в других случаях?

Просто макросы это не "примитивная" подстановка в текст программы чего бы то ни было как просто подмена строки strreplace(). Они работают на уровне лексем - несмотря на то что между тоукенами нет пробелов, но препроцессор уже делит их на разные лексемы - поэтому у тебя "иллюзии" что где то пробелы вставляются где то нет - на деле просто для компилятора и без пробелов это уже разные лексемы. Действительно во избежание элементарных штук нежелательного "склеивания" лексем если бы это была тупая подстановка строк.

#3
23:21, 15 янв. 2013

=A=L=X=
> макросы это не "примитивная" подстановка в текст программы
AFAIK в стандарте языка С++ написано, что макросы занимаются подстановкой текста в текст программы. Или я не прав?

Короче, вот это по стандарту должно компилироваться или нет?

#define F()1
int main()
{
  int value=F()1;
  return value;
}

#4
0:04, 16 янв. 2013

Adler
> Короче, вот это по стандарту должно компилироваться или нет?
Нет.

Сначала выполняется разбивка текста на токены и только потом подстановка. Препроцессор подставляет набор токенов, а не строки. Склеивание токенов происходит только при явном указании с помощью ##.

#5
2:15, 16 янв. 2013

}:+()___ [Smile]
> Препроцессор подставляет набор токенов, а не строки
Значит выполнив стадию препроцессора без компиляции мы получаем в выходном текстовом файле не совсем корректные данные, т.к информация о токенах теряется? Неожиданно. И как теперь посмотреть что на самом деле было передано компилятору препроцессором?


Какое-то совсем странное поведение:

//test.cpp
#define F(A)A
int main()
{
  F(
    int value=10;
    //add_comment()
  );
  return value;
}
cl.exe /P /EP /C /nologo /EHcs test.cpp
//test.i
int main()
{
  //add_comment()int value=10;;
  return value;
}
O_o

#6
7:21, 16 янв. 2013

Adler
> AFAIK в стандарте языка С++ написано, что макросы занимаются подстановкой
> текста в текст программы. Или я не прав?

Нет, неправ. Тогда бы:

#define X Y
int XYZ = 0;

превратилось бы в
int YYZ=0;
но как ты знаешь такого не происходит - препроцессор оперирует не просто строками, а токенами, т.е. понимает что является одним идентификатором, а что другим. И результат является тоже разбитым на токены, уж как точно он это делает я не знаю, вставляя пробелы или просто сразу в компиле дробя на токены, но это неважно.

#7
6:09, 17 янв. 2013
> токены
> токенов
> токенами
> токены
Возможно, вы имели ввиду лексемы.
#8
6:30, 17 янв. 2013

Fla
> Возможно, вы имели ввиду лексемы.

http://ru.wikipedia.org/wiki/%D0%A2%D0%BE%D0%BA%D0%B5%D0%BD
Но так да - лексама будет яснее.

ПрограммированиеФорумОбщее

Тема в архиве.