Может ли препроцессор C выполнять целочисленную арифметику? - PullRequest
21 голосов
/ 13 октября 2009

Как говорится в вопросе, способен ли препроцессор C сделать это?

например:.

#define PI 3.1416
#define OP PI/100
#define OP2 PI%100

Есть ли способ рассчитать OP и / или OP2 на этапе предварительной обработки?

Ответы [ 5 ]

28 голосов
/ 13 октября 2009

Целочисленная арифметика? Запустите следующую программу, чтобы узнать:

#include "stdio.h"
int main() {
    #if 1 + 1 == 2
        printf("1+1==2\n");
    #endif
    #if 1 + 1 == 3
        printf("1+1==3\n");
    #endif
 }

Ответ «да», есть способ заставить препроцессор выполнять целочисленную арифметику, то есть использовать его в условии препроцессора.

Обратите внимание, что ваши примеры не являются целочисленной арифметикой. Я только что проверил, и препроцессор gcc завершится неудачей, если вы попытаетесь сделать сравнение с плавающей запятой. Я не проверял, допускает ли когда-либо стандарт арифметику с плавающей запятой в препроцессоре.

Обычное расширение макроса не оценивает целочисленные выражения, оно оставляет его компилятору, что можно увидеть по предварительной обработке (-E в gcc):

#define ONEPLUSONE (1 + 1)
#if ONEPLUSONE == 2
    int i = ONEPLUSONE;
#endif

Результат равен int i = (1 + 1); (плюс, вероятно, некоторые вещи, указывающие имена исходных файлов и номера строк и тому подобное).

17 голосов
/ 13 октября 2009

Код, который вы написали, на самом деле не заставляет препроцессор выполнять какие-либо вычисления. #Define выполняет простую замену текста, поэтому с этим определено:

#define PI 3.1416
#define OP PI/100

Этот код:

if (OP == x) { ... }

становится

if (3.1416/100 == x) { ... }

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

if (0.031416 == x) { ... }

Но это компилятор, а не препроцессор.

Чтобы ответить на ваш вопрос, да, препроцессор МОЖЕТ выполнить некоторую арифметику. Это видно, когда вы пишете что-то вроде этого:

#if (3.141/100 == 20)
   printf("yo");
#elif (3+3 == 6)
   printf("hey");
#endif
6 голосов
/ 07 октября 2010

Да, это можно сделать с помощью Boost Preprocessor. И он совместим с чистым Си, так что вы можете использовать его в программах на Си только с компиляциями на Си. Ваш код включает в себя числа с плавающей запятой, поэтому я думаю, что это должно быть сделано косвенно.

#include <boost/preprocessor/arithmetic/div.hpp>
BOOST_PP_DIV(11, 5) // expands to 2
#define KB 1024
#define HKB BOOST_PP_DIV(A,2)
#define REM(A,B) BOOST_PP_SUB(A, BOOST_PP_MUL(B, BOOST_PP_DIV(A,B)))
#define RKB REM(KB,2)

int div = HKB;
int rem = RKB;

Это препроцессирует до (проверьте с помощью gcc -S)

int div = 512;
int rem = 0;

Благодаря этой теме.

6 голосов
/ 13 октября 2009

ДА , я имею в виду: он может делать арифметику:)

Как показано в 99 бутылках пива .

4 голосов
/ 13 октября 2009

Да.

Не могу поверить, что еще никто не связывался с каким-то запутанным победителем конкурса Си. Парень реализовал ALU в препроцессоре с помощью рекурсивных включений. Здесь является реализацией, а здесь является чем-то вроде объяснения.

Теперь, тем не менее, вы не хотите делать то, что сделал этот парень. Это забавно и все, но посмотрите на время компиляции в его файле подсказок (не говоря уже о том, что полученный код не поддерживается). Чаще всего люди используют препроцессор строго для замены текста, и вычисление постоянной целочисленной арифметики происходит либо во время компиляции, либо во время выполнения.

Как уже отмечали другие, вы можете сделать некоторую арифметику в операторах #if.

...