Не уверен насчет Oracle или sql-server, но в MySQL вы можете просто использовать *
, как обычно.
mysql> select count(id), count(id)*10 from tablename;
+-----------+--------------+
| count(id) | count(id)*10 |
+-----------+--------------+
| 961 | 9610 |
+-----------+--------------+
1 row in set (0.00 sec)
do ... while
и if ... else
там для создания его так, чтобы точка с запятой после макроса всегда означала то же самое. Скажем, у Вас было что-то как Ваш второй макрос.
#define BAR(X) f(x); g(x)
Теперь, если необходимо было использовать BAR(X);
в if ... else
оператор, где тела, если бы оператор не был обернут в фигурные скобки, Вы получили бы плохое удивление.
if (corge)
BAR(corge);
else
gralt();
вышеупомянутый код расширился бы в [1 124]
if (corge)
f(corge); g(corge);
else
gralt();
, который является синтаксически неправильным, поскольку еще больше не связывается с если. Это не помогает обернуть вещи в фигурные скобки в рамках макроса, потому что точка с запятой после фигурных скобок является синтаксически неправильной.
if (corge)
{f(corge); g(corge);};
else
gralt();
существует два способа решить проблему. Первое должно использовать запятую для упорядочивания операторов в рамках макроса, не отнимая у него его способность действовать как выражение.
#define BAR(X) f(X), g(X)
вышеупомянутая версия панели BAR
разворачивает вышеупомянутый код в то, что следует, который синтаксически корректен.
if (corge)
f(corge), g(corge);
else
gralt();
Это не работает, если вместо [1 113] у Вас более сложное тело кода, который должен войти в его собственный блок, сказать, например, для объявления локальных переменных. В наиболее общем случае решение состоит в том, чтобы использовать что-то как [1 114], чтобы заставить макрос быть отдельным оператором, который берет точку с запятой без беспорядка.
#define BAR(X) do { \
int i = f(X); \
if (i > 4) g(i); \
} while (0)
Вы не должны использовать do ... while
, Вы могли приготовить что-то с [1 116] также, хотя, когда if ... else
расширяется в if ... else
, это еще приводит к" свисание ", который еще мог сделать существующее свисание проблемой еще тяжелее для нахождения, как в следующем коде.
if (corge)
if (1) { f(corge); g(corge); } else;
else
gralt();
точка должна израсходовать точку с запятой в контекстах, где повисшая точка с запятой ошибочна. Конечно, это могло (и вероятно должен), будьте обсуждены в этой точке, которую было бы лучше объявить BAR
как фактическая функция, не макрос.
, Таким образом, эти do ... while
там для работы вокруг недостатков препроцессора C. Когда те руководства по стилю C говорят Вам откладывать препроцессор C, это - вид вещи, по поводу которой они волнуются.
Макросы, копируют/вставляют части текста, препроцессор вставит подлинный код; автор макроса надеется, что замена произведет допустимый код.
существует три хороших "подсказки" для преуспевания в этом:
, Нормальный код обычно заканчивается точкой с запятой. Если пользовательский код представления, не нуждающийся один...
doSomething(1) ;
DO_SOMETHING_ELSE(2) // <== Hey? What's this?
doSomethingElseAgain(3) ;
Это означает, что пользователь ожидает, что компилятор произведет ошибку, если точка с запятой будет отсутствовать.
, Но реальная очень хорошая причина то, что в некоторое время, автор макроса должен будет, возможно, заменить макрос подлинной функцией (возможно, встроенный). Таким образом, макрос должен действительно , ведут себя как один.
, Таким образом, у нас должна быть точка с запятой необходимости макроса.
Как показано в ответе jfm3, иногда макрос содержит больше чем одну инструкцию. И если макрос используется в, если оператор, это будет проблематично:
if(bIsOk)
MY_MACRO(42) ;
Этот макрос мог быть расширен как:
#define MY_MACRO(x) f(x) ; g(x)
if(bIsOk)
f(42) ; g(42) ; // was MY_MACRO(42) ;
Эти g
функция будет выполняться независимо от значения [1 113].
Это означает, что нам, должно быть, придется добавить объем к макросу:
#define MY_MACRO(x) { f(x) ; g(x) ; }
if(bIsOk)
{ f(42) ; g(42) ; } ; // was MY_MACRO(42) ;
, Если макрос - что-то как:
#define MY_MACRO(x) int i = x + 1 ; f(i) ;
у Нас могла быть другая проблема в следующем коде:
void doSomething()
{
int i = 25 ;
MY_MACRO(32) ;
}
, поскольку это расширилось бы как:
void doSomething()
{
int i = 25 ;
int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}
Этот код не скомпилирует, конечно. Так, снова, решение использует объем:
#define MY_MACRO(x) { int i = x + 1 ; f(i) ; }
void doSomething()
{
int i = 25 ;
{ int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ;
}
код ведет себя правильно снова.
существует одна идиома C/C++, которая производит этот эффект:/цикл с условием продолжения:
do
{
// code
}
while(false) ;
/в то время как может создать объем, таким образом инкапсулируя код макроса, и нуждается в точке с запятой в конце, таким образом расширяясь в код, нуждающийся один.
премия?
компилятор C++ оптимизирует далеко/цикл с условием продолжения, как факт его постусловие является ложью, известен во время компиляции. Это означает что макрос как:
#define MY_MACRO(x) \
do \
{ \
const int i = x + 1 ; \
f(i) ; g(i) ; \
} \
while(false)
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
MY_MACRO(42) ;
// Etc.
}
расширится правильно как [1 137]
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
do
{
const int i = 42 + 1 ; // was MY_MACRO(42) ;
f(i) ; g(i) ;
}
while(false) ;
// Etc.
}
и тогда скомпилирован и оптимизирован далеко как [1 138]
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
{
f(43) ; g(43) ;
}
// Etc.
}
@jfm3 - у Вас есть хороший ответ на вопрос. Вы могли бы также хотеть добавить, что макро-идиома также предотвращает возможно более опасный (потому что нет никакой ошибки), непреднамеренное поведение с простым, 'если' операторы:
#define FOO(x) f(x); g(x)
if (test) FOO( baz);
расширяется до:
if (test) f(baz); g(baz);
, который синтаксически корректен, таким образом, нет никакой ошибки компилятора, но имеет, вероятно, непреднамеренное последствие, которым будут всегда называть g ().
Я не думаю, что это было упомянуто, так полагайте, что это
while(i<100)
FOO(i++);
было бы переведено в
while(i<100)
do { f(i++); g(i++); } while (0)
уведомление, как i++
оценен дважды макросом. Это может привести к некоторым интересным ошибкам.
Хотя ожидается, что компиляторы оптимизируют циклы do {...} while (false);
, существует другое решение, которое не требует этой конструкции. Решение состоит в использовании оператора запятой:
#define FOO(X) (f(X),g(X))
или даже более экзотично:
#define FOO(X) g((f(X),(X)))
Хотя это будет хорошо работать с отдельными инструкциями, он не будет работать в тех случаях, когда переменные конструируются и используются как часть #define
:
#define FOO(X) (int s=5,f((X)+s),g((X)+s))
В этом случае нужно будет использовать конструкцию do / while.