c препроцессором добавить пробел при объединении чисел со знаком - PullRequest
0 голосов
/ 16 декабря 2018

Кажется, что препроцессор добавляет пробел при объединении токенов, которые являются числами со знаком.Я попытался это:

#define DECL_FL(IE) 1e##IE##f

float val[] = 
{
    DECL_FL(12),
    DECL_FL(-12),
    DECL_FL(+12),
};

я запускаю препроцессор:

$ gcc test.c -E
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test.c"

float val[] =
{
 1e12f,
 1e- 12f,
 1e+ 12f,
};

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

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Короткая версия такова, что +12 не является токеном препроцессора и не является -12;скорее, каждый из них является двумя токенами препроцессора (а именно, + и - являются пунктуаторами; 12 отдельно является числом pp).

По сути, мы имеем дело с числом pp,Итак, вот правила грамматики для чисел pp:

<em>pp-number</em>: <em>digit</em> <strong>.</strong> <em>digit</em> <em>pp-number</em> <em>digit</em> <em>pp-number</em> <em>identifier-nondigit</em> <em>pp-number</em> <strong>e</strong> <em>sign</em> <em>pp-number</em> <strong>E</strong> <em>sign</em> <em>pp-number</em> <strong>p</strong> <em>sign</em> <em>pp-number</em> <strong>P</strong> <em>sign</em> <em>pp-number</em> <strong>.</strong> Обратите внимание, что 1, 1e+, 1e+12 и 1e+12f - все числа pp, но +12 и -12 нет.Это то, что вас кусает.

Согласно правилам препроцессора, параметр в списке замены заменяется последовательностью токена аргумента;затем применяется каждый ##.Приложение удаляет ## и объединяет предыдущий токен со следующим токеном.Если эта комбинация не является допустимым токеном препроцессора, результат не определен.(Для справки токен препроцессора может быть именем заголовка, идентификатором, номером pp, символьной константой, строковым литералом, пунктуатором или непробельным символом, который не является одним из них; вот и все).

При применении 1e ## IE ## f с IE равным +12, вы, по сути, делаете <<code>1e> ## <<code>+> <<code>12> ## <<code>f>, используя угловые скобкидля обозначения отдельных токенов.Обе вставки, независимо от порядка (что хорошо, поскольку порядок ## не указан), будут давать действительные числа pp <<code>1e+> и <<code>12f>.Но результат оставляет вас с <<code>1e+> <<code>12f>, а не с желаемым <<code>1e+12f>.

Как мне избежать этого?

К сожалению, вы должны отказатьсяпри передаче +12 и -12 последовательностей токенов в качестве аргумента.Вы можете принять +, 12 в качестве двух аргументов, но вы должны быть осторожны при объединении этих шагов, поскольку порядок операторов ## не указан и +12 не является допустимым токеном препроцессора (в противном случае он может работать, но будетразрешено не ... и , что - это потенциально кошмарная бомба замедленного действия):

#define PASTE(A,B) A##B
#define DECL_FL(IE) 1e##IE##f
#define DECL_FL_SGN(S,IE) PASTE(1e##S,IE##f)
float val[] = 
{
    DECL_FL(12),
    DECL_FL_SGN(+,12),
    DECL_FL_SGN(-,12),
};

... или вы можете просто использовать специальный макрос для знака;строго говоря, поскольку 1e12f и 1e+12f имеют одно и то же значение (и никто не увидит его в любом случае, если они не запустят препроцессор), вы можете обойтись только двумя макросами:

#define DECL_FL(IE) 1e##IE##f
#define DECL_FL_E_NEG(IE) 1e-##IE##f
float val[] = 
{
    DECL_FL(12),
    DECL_FL_E_NEG(12),
    DECL_FL(12),
};
0 голосов
/ 16 декабря 2018

## является оператором вставки токена, он не будет работать, если действительный токен не сформирован после его использования, в соответствии с C 1e+12f не является допустимым токеном препроцессора, поэтому он пытается вставить пространство или может привести к непредвиденному поведениюВы можете найти его в следующей документации.

http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html

...