C语言 是否可以在#define 中使用 if 语句?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12989298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:10:20  来源:igfitidea点击:

Is it possible to use a if statement inside #define?

cif-statementmacrosc-preprocessor

提问by Frey1337

I'm trying to make a macro with the following formula: (a^2/(a+b))*b, and I want to make sure that the there will be no dividing by zero.

我正在尝试使用以下公式创建一个宏:(a^2/(a+b))*b,并且我想确保不会被零除。

#define SUM_A( x, y ) if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}

and then I call the macro inside main:

然后我在 main 中调用宏:

float a = 40, b = 10, result; 
result = SUM_A(a, b); 
printf("%f", result);

I've tried using brackets around the if function but I keep getting syntax errors before the if statement. I've also tried using return, but I read somewhere that you're not supposed to use that in define.

我试过在 if 函数周围使用括号,但在 if 语句之前我不断收到语法错误。我也试过使用 return,但我在某处读到你不应该在定义中使用它。

回答by tomahh

You can not use if statement, because #defineis interpret by the preprocessor, and the output would be

你不能使用 if 语句,因为它#define是由预处理器解释的,输出将是

 result=if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}

which is wrong syntax.

这是错误的语法。

But an alternative is to use ternary operator. Change your define to

但另一种方法是使用三元运算符。将您的定义更改为

#define SUM_A( x, y )  ((x) == 0 || (y) == 0 ? 0 : ( ( ( (x) * (x) ) / ( ( x ) + ( y ) ) ) * ( y ) ))

Remember to always put your define between parentheses, to avoid syntax error when replacing.

请记住始终将定义放在括号之间,以避免替换时出现语法错误。

回答by Saeed Baig

As far as I know, what you're trying to do (use ifstatement and then return a value from a macro) isn't possible in ISO C... but it is somewhat possible with statement expressions(GNU extension).

据我所知,您尝试执行的操作(使用if语句然后从宏中返回一个值)在 ISO C 中是不可能的……但是语句表达式(GNU 扩展)在某种程度上是可能的。

Since #defines are essentially just fancy text find-and-replace, you have to be really careful about how they're expanded. I've found that this works on gccand clang:

由于#defines 本质上只是花哨的文本查找和替换,因此您必须非常小心它们的扩展方式。我发现这适用于gccclang

#define SUM_A(x, y)                                     \
({                                                      \
    float answer;                                       \
    if ((x) == 0 || (y) == 0) {                         \
        answer = 0;                                     \
    } else {                                            \
        answer = ((float)((x)*(x)) / ((x)+(y))) * (y);  \
    }                                                   \
    answer;                                             \
})
// Typecasting to float necessary, since int/int == int in C

Brief explanation of the things in this macro:

简单解释一下这个宏里面的东西:

  • The \at the end of each line is to signal line continuation (i.e. to tell the compiler "this macro continues on the next line")
  • The ({is a statement expression (GNU extension; not part of standard C).
  • Though not strictly necessary, it's safer to wrap up each use of the parameter/s in parentheses to avoid operator-precedence gotchas. For example, if xwas 2+1, then (x)*(x)would expand to (2+1)*(2+1), which is 9 (what we wanted), but x*xwould expand to 2+1*2+1, which is 5 (not what we wanted)
  • In statement expressions, the last line functions like the returnvalue (hence the answer;at the end)
  • \每一行的末尾是信号线延续(即告诉编译器“这个宏继续到下一行”)
  • ({是一个语句表达式(GNU 扩展;不是标准 C 的一部分)。
  • 尽管不是绝对必要的,但将参数的每次使用都括在括号中以避免运算符优先级问题更安全。例如,如果x2+1,那么(x)*(x)会扩展到(2+1)*(2+1)9(我们想要的),但x*x会扩展到2+1*2+15(不是我们想要的)
  • 在语句表达式中,最后一行的功能类似于return值(因此answer;在末尾)

This should give you the result you're looking for, and there's no reason it can't be extended to include multiple else ifs as well (though as other answers have pointed out, it's probably better to use the ternary operator if you can).

这应该为您提供您正在寻找的结果,并且没有理由不能将其扩展为包含多个else ifs(尽管正如其他答案所指出的那样,如果可以的话,最好使用三元运算符)。

回答by Fred Foo

ifintroduces a statement, not an expression. Use the "ternary" (conditional) operator:

if引入一个语句,而不是一个表达式。使用“三元”(条件)运算符:

#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x)) / ((x) + (y))) * (y)))

Alternatively, make this an inlinefunction:

或者,将其设为inline函数:

inline float sum_a(float x, float y)
{
    if (x == 0 || y == 0)
        return 0;
    else
        return ((x * x) / (x + y)) * y;
}

This avoids the problem of multiple evaluation of xand/or yand is much more readable, but it does fix the types of xand y. You can also drop the inlineand let the compiler decide whether inlining this function is worthwhile (inlineis not a guarantee that it will perform inlining).

这避免了x和/或的多重评估问题并且y更具可读性,但它确实修复了x和的类型y。您也可以删除inline并让编译器决定内联此函数是否值得(inline并不能保证它会执行内联)。

回答by chqrlie

There are multiple problems with your macro:

您的宏存在多个问题:

  • it expands to a statement, so you cannot use it as an expression

  • the arguments are not properly parenthesized in the expansion: invoking this macro with anything but variable names or constants will produce problems.

  • the arguments are evaluated multiple times: if you invoke the macro with arguments that have side effects, such as SUM_A(a(), b())or SUM_A(*p++, 2), the side effect will occur multiple times.

  • 它扩展为语句,因此您不能将其用作表达式

  • 扩展中的参数没有正确加括号:用变量名或常量以外的任何东西调用这个宏会产生问题。

  • 参数被评估多次:如果您使用具有副作用的参数调用宏,例如SUM_A(a(), b())or SUM_A(*p++, 2),副作用将发生多次。

To avoid all these problems, use a function, possibly defined as static inlineto help the compiler optimize more (this is optional and modern compilers do this automatically):

为了避免所有这些问题,请使用一个函数,可能定义为static inline帮助编译器优化更多(这是可选的,现代编译器会自动执行此操作):

static inline int SUM_A(float x, float y) {
    if (x == 0 || y == 0)
        return 0; 
    else
        return x * x / (x + y) * y;
}

Notes:

笔记:

  • this function uses floating point arithmetic, which the macro would not necessarily, depending on the actual types of its arguments.
  • the test does not prevent division by zero: SUM_A(-1, 1) still performs one.
  • division by zero is not necessarily a problem: with floating point arguments, it produces an Infinity or a NaN, not a runtime error.
  • 此函数使用浮点运算,宏不一定会使用浮点运算,具体取决于其参数的实际类型。
  • 该测试不会阻止被零除: SUM_A(-1, 1) 仍然执行 1。
  • 除以零不一定是一个问题:对于浮点参数,它会产生 Infinity 或 NaN,而不是运行时错误。

回答by Alex D

The problem is that an ifstatement is not an expression, and doesn't return a value. Besides, there is no good reason to use a macro in this case. In fact, it could cause very serious performance problems (depending on what you pass as macro arguments). You should use a function instead.

问题是if语句不是表达式,并且不返回值。此外,在这种情况下没有充分的理由使用宏。事实上,它可能会导致非常严重的性能问题(取决于您作为宏参数传递的内容)。您应该改用函数。

回答by Sarena Meas

YES you can have an if statement in a macro. You need to format it correctly. Here is an example:

是的,您可以在宏中使用 if 语句。您需要正确格式化它。下面是一个例子:

#define MY_FUNCTION( x )  if( x ) { PRINT("TRUE"); } else { PRINT("FALSE"); } 

回答by TheWhitde

I use macros with conditions quite a bit and they do have a legit use.

我经常使用带有条件的宏,它们确实有合法用途。

I have a few structures that are essentially blobs and everything is just a uint8_t stream.

我有一些本质上是 blob 的结构,一切都只是一个 uint8_t 流。

To make internal structures more readable I have conditional macros.

为了使内部结构更具可读性,我有条件宏。

Example...

例子...

#define MAX_NODES 10
#define _CVAL16(x)(((x) <= 127) ? (x) : ((((x) & 127) | 0x80) ), ((x) >> 7))  // 1 or 2 bytes emitted <= 127 = 1 otherwise 2

Now to use the macro inside an array ...

现在在数组中使用宏...

uint8_t arr_cvals[] = { _CVAL16(MAX_NODES), _CVAL16(345) };

Three bytes are emitted in the array, 1st macro emits 1 and the second 2 bytes. This is evaluated at compile time and just makes the code more readable.

数组中发出三个字节,第一个宏发出 1 个字节,第二个宏发出 2 个字节。这是在编译时评估的,只是使代码更具可读性。

I also have... for example...

我也有……比如……

#define _VAL16(x) ((x) & 255), (((x) >> 8) & 255)

For the original problem... maybe the person wants to use the results with constants, but once again really comes down to where and how it's to be used.

对于最初的问题......也许这个人想要使用带有常量的结果,但再次真正归结为在哪里以及如何使用它。

#define SUM_A(x, y) (!(x) || !(y)) ? 0 : ((x) * (x) / ((x) + (y)) * (y))
float arr_f[] = { SUM_A(0.5f, 0.55f), SUM_A(0.0f, -1.0f), SUM_A(1.0f, 0.0f) };

At runtime can have...

在运行时可以有...

float x;
float y;

float res = SUM_A(x,y); // note ; on the end

I have a program that creates fonts that are included as code inside C programs and most values are wrapped around macros that split 32 bit values into 4 bytes, float into 4 bytes, etc.

我有一个程序可以创建作为代码包含在 C 程序中的字体,并且大多数值都包裹在将 32 位值拆分为 4 个字节、浮点数为 4 个字节等的宏周围。

回答by pmg

You can convert the conditional statement into a simple expression. Conditions evaluate to 0or 1

您可以将条件语句转换为简单的表达式。条件评估为01

// pseudo-code
// if (<something>) { 0; } else { 42; }
// if (!<something>) { 42; } else { 0; }
// !<something> * 42;

In your specific case

在您的具体情况下

// if ((x == 0) || (y == 0)) { 0; } else { (x)(y)expression; }
// if ((x != 0) && (y != 0)) { (x)(y)expression; }
// ((x != 0) && (y != 0)) * ( (x)(y)expression );