2009-10-13 12 views
18

Zgodnie z pytaniami, czy preprocesor jest w stanie to zrobić?Czy preprocesor C może wykonywać arytmetykę liczb całkowitych?

Np .:

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

Czy istnieje jakiś sposób, PO i/lub OP2 oblicza się w fazie przeróbki?

+4

PI jest liczbą całkowitą z przykładu; zatem OP ani OP2 nie będą liczbami całkowitymi, jeśli preprocesor był zmuszony je ocenić. A operandy "%" nie mogą być liczbami zmiennoprzecinkowymi. –

Odpowiedz

25

Arytmetyka liczb całkowitych? Uruchom następujący program, aby dowiedzieć się:

#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 
} 

odpowiedź brzmi „tak”, nie ma sposobu, aby preprocesor wykonać arytmetyki liczb całkowitych, która jest wykorzystanie go w stanie preprocesora.

Pamiętaj jednak, że Twoje przykłady nie są arytmetyczne. Właśnie sprawdziłem i preprocesor gcc nie powiedzie się, jeśli spróbujesz dokonać porównania float. Nie sprawdziłem, czy standard pozwala na arytmetykę zmiennoprzecinkową w preprocesorze.

Regularne makro ekspansja nie ocenia wyrażeń całkowitych, pozostawia go do kompilatora, jak widać przez przerób (-E w gcc) następujące:

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

wynik jest int i = (1 + 1); (plus prawdopodobnie niektóre rzeczy w celu wskazania nazw plików źródłowych i numerów linii itp.).

+6

Chris: Teraz żyjemy w przyszłości i chociaż wciąż brakuje samochodów latających, pojawiły się domyślne wartości powrotu z głównej funkcji! –

+11

@Chris: ścisły nawias klamrowy, osiągający wartość "zwraca wartość 0" (5.1.2.2.3, zakończenie programu). Jeśli nie mogę przyjąć standardowego C w pytaniu oznaczonym "C", to do czego zmierza świat? Nie możesz znaleźć kogoś, kto używa // - stylów komentarzy w kodzie, który może być widziany przez kompilator C89 i zamiast tego narzekać? ;-) –

+0

@Chris - Klamra zamykająca? :-) –

13

Kod, który napisałeś, nie powoduje, że preprocesor wykonuje jakiekolwiek obliczenia. #define robi prostą wymianę tekstową, więc o to określono:

#define PI 3.1416 
#define OP PI/100 

ten kod:

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

staje

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

a następnie pobiera skompilowany. Kompilator z kolei może zdecydować się na taki wyraz i obliczyć w czasie kompilacji i stworzyć odpowiednik kodu do tego:

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

Ale to kompilator nie preprocesor.

Aby odpowiedzieć na pytanie, tak, preprocesor CAN może wykonać pewną operację arytmetyczną. Widać to, gdy piszesz coś takiego:

#if (3.141/100 == 20) 
    printf("yo"); 
#elif (3+3 == 6) 
    printf("hey"); 
#endif 
+3

Niestety, jeśli wypróbujesz swój warunkowy fragment kompilacji, otrzymasz wiadomość od GCC:' x.c: 5: 6: error: stała zmiennoprzecinkowa w wyrażeniu preprocesora'. Możesz wykonywać arytmetykę liczb całkowitych za pomocą pre-procesora C; nie można z nim wykonywać arytmetyki zmiennoprzecinkowej. –

+0

wygląda jak skróty gcc tutaj, Stroustrup C++ wydanie 2 r.16.5 '#if wyrażenie-stały',' wyrażenie.5.5 wyrażenie stałe': "... zmienne stałe muszą być rzucane do typów integralnych". – denis

4

Tak.

Nie mogę uwierzyć, że nikt jeszcze nie połączył się z pewnym zaciemnionym zwycięzcą konkursu C. Facet zaimplementował ALU w preprocesorze poprzez rekursywne obejmuje. Here jest implementacją, a here jest wyjaśnieniem.

Powiedziałeś, że nie chcesz robić tego, co zrobił ten facet.To zabawne i wszystko, ale spójrz na czasy kompilacji w jego pliku podpowiedzi (nie wspominając o tym, że wynikowy kod jest nieosiągalny). Częściej ludzie używają preprocesora wyłącznie do zastępowania tekstu, a ocena arytmetyczna stałej całkowitej dzieje się albo w czasie kompilacji, albo w czasie wykonywania.

Jednak inni zauważyli, że możesz wykonać pewną arytmetykę w instrukcjach #if.

+1

http://stackoverflow.com/questions/652788/what-is-the-worst-real-world-macros-pre-processor-abuse-youve-ever-come-across/1242177#1242177 - chaos-pp . Nadużycie preprocesora ze stylem. –

6

Tak, można to zrobić za pomocą Preprocessora doładowania. Jest kompatybilny z czystym C, więc możesz go używać w programach C tylko z kompilacjami C. Twój kod zawiera liczby zmiennoprzecinkowe, więc myślę, że to musi być zrobione pośrednio.

#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; 

to preprocesses do (kontrola gcc -S)

int div = 512; 
int rem = 0; 

Dzięki this thread.