2014-01-16 2 views
0

У меня есть этот простой код, который преобразует между степенями Farehnheit и градусами Celcius. Я определил некоторые макросы, чтобы сделать это, но я получаю некоторые странные результаты, когда я его использую. Я использую этот метод, когда absoluteTemp = 373,15 (точка кипения воды в кельвине).Макросы C++: порядок отличий приоритета?

#define kelvinToCelc(k) k - 273.15 
#define celcToFahren(c) (9.0/5.0) * c + 32 

double x = kelvinToCelc(absoluteTemp);    // 100 
double y = celcToFahren(x);       // 212 
double z = celcToFahren(kelvinToCelc(absoluteTemp)); // 430.52??? 
return celcToFaren(kelvinToCelc(absoluteTemp)); 
+1

Это было бы намного лучше, чем функции. И http://coliru.stacked-crooked.com/a/3e592437849fd9ca – chris

+0

используйте встроенную функцию вместо макроса, чтобы сохранить некоторые проблемы. –

ответ

3

После расширения макроса в

double z = celcToFahren(kelvinToCelc(absoluteTemp)); 

становится

double z = (9.0/5.0) * absoluteTemp - 273.15 + 32 

Вам нужно добавить скобки макросов

#define kelvinToCelc(k) (k - 273.15) 
#define celcToFahren(c) ((9.0/5.0) * c + 32) 
+2

И второй. Только представьте, '' '' 'x + y'. – chris

+1

Вероятно, вы должны добавить paranthesis ко всем макросам, чтобы избежать приоритета, прикручивающего вашу математику. – user2176127

+0

Я принял ваш ответ, потому что он предложил хорошее объяснение и решение – michaelsnowden

1

Макросы просты - Просто текст замены

т.е.

double z = celcToFahren(kelvinToCelc(absoluteTemp)); 

становится

double z = (9.0/5.0) * kelvinToCelc(absoluteTemp) + 32 

Тогда становится

double z = (9.0/5.0) * absoluteTemp - 273.15 + 32 

Теперь просто сделать математику

т.е.

double z = (9.0/5.0) * 373.15 - 273.15 + 32; 
+0

Вы говорите, что макросы просты. Я приговариваю вас к часу взгляда на реализацию Boost.Preprocessor (или довольно много других библиотек, даже с этими замечательными утилитами). – chris

+0

@chris - Я нахожу их простыми - просто используйте карандаш и резину –

+0

http://i.imgur.com/2bXTrfc.jpg – chris

0

Для макросов, она просто опирается на текстовой замене. Так что это эквивалентно:

double z = (9.0/5.0) * absoluteTemp - 273.15 + 32; 

Вот почему вы получили неправильный результат.

Edit:

  1. Попробуйте использования (встроенные) функции вместо даже вы можете заставить его работать, добавив больше скобки: (см # 2)

    #define celcToFahren(c) ((9.0/5.0) * (c) + 32) 
    
  2. Макросы также являются с ошибкой потому что они полагаются на текстовую подстановку и не выполняют проверку типов. За дополнительной информацией обращайтесь к here.

+0

Редактировать 1 - не очень хорошее решение. 'celcToFahren (x) * 5', например, приведет к нежелательному поведению снова (значение' 32' будет умножено на '5'). – user2176127

+0

@ user2176127 Исправлено добавлением БОЛЬШИХ круглых скобок. Благодарю. – herohuyongtao

+0

Кажется, Lisp - это просто арифметические идиомы макросов C, превращенные в язык. – chris

1

Если вы собираетесь использовать макросы, облегчите жизнь с помощью круглых скобок

#define kelvinToCelc(k) (k) - 273.15 
#define celcToFahren(c) (9.0/5.0) * (c) + 32 

Это помогает предотвратить неожиданные результаты, которые вы видите. Причины, о которых уже указывалось в других сообщениях

0

Только одно, что я должен добавить к другим ответам, попробуйте запустить только препроцессор и посмотреть на выход, например: g ++ -E -P main.каст

2

Старое правило было: Используйте больше скобки в макросах вокруг всего:

#define kelvinToCelc(k) ((k) - 273.15) 
#define celcToFahren(c) ((9.0/5.0) * (c) + 32) 

Уведомления скобки вокруг всего макро и всех макро аргументов

Новое правило: Использовать встроенные функции Они имеют проверку типов, оценивают аргументы только один раз и потому, что им не требуется столько скобок *

Примечание: * Могут применяться некоторые исключения, это не один из них

Это то, что выглядит как встроенные функции

inline double kelvinToCelc(double k) 
{ 
    return k - 273.15; 
} 

inline double kelvinToCelc(double c) 
{ 
    return (9.0/5.0) * c + 32; 
} 

Обратите внимание, что вы должны поставить inline и тип возвращаемого перед именем, добавить типы всех аргументов, и добавить ; в конце

Обратите внимание, как вы можете использовать новые строки, чтобы сделать его более удобным для чтения, а также, так что вы можете выйти в него в отладчик

+0

Lovely. Спасибо Glenn – michaelsnowden

+0

Примечание: функции могут также быть 'constexpr' в C++ 11. – Jarod42

0

ответ на этот вопрос 431,52 правильно. Он расширился следующим образом

(9.0/5.0) * 373.15 - 272.15 + 32 

В математике [* и /] имеют приоритет над [+ и -]. Таким образом, уравнение расширяется как

((9.0/5.0) * 373.15) - 272.15 + 32 
(671.67) - 272.15 + 32 
399.52 + 32 
431.52 

[* и /] имеют одинаковый приоритет, так что порядок не имеет значения, а так же [+ и -] имеют такой же приоритет, поэтому порядок их выполнения не имеет значения.

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