执行“#define”和内联行为相同吗?

发布于 2024-11-18 11:03:59 字数 577 浏览 3 评论 0原文

我的标题之一中有一些简短的定义,如下所示:

#define ROUND_DOWN(a,b)   (a)-(a)%(b)

例如

ROUND_DOWN(178,32) = 160

,但是如果我将其传递给它:

ROUND_DOWN(160*2, 32);

那么它会像这样编译?

(160*2)-(160*2)%(32), 

这只是更多的处理,因为它做了 160*2 两次。

我想知道内联函数的行为是否相同?例如,

inline int RoundDown(int a, int b)
{
return (a)-(a)%(b)
}

160*2 会作为 320 存储在“int a”中,然后计算会起作用,还是会与定义的行为相同?

一个更好的例子是调用:

RoundDown((x+x2)*zoom, tile_width);

I have some short defines in one of my headers like this:

#define ROUND_DOWN(a,b)   (a)-(a)%(b)

e.g.

ROUND_DOWN(178,32) = 160

But if I pass this to it:

ROUND_DOWN(160*2, 32);

then it gets compiled like this?

(160*2)-(160*2)%(32), 

which is just more processing as it does 160*2 twice..

I'm wondering if inline functions behave in the same way? e.g.

inline int RoundDown(int a, int b)
{
return (a)-(a)%(b)
}

Would 160*2 get stored in "int a" as 320 and then the calculation would work, or would it behave the same as the define?

A better example is calling:

RoundDown((x+x2)*zoom, tile_width);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

临风闻羌笛 2024-11-25 11:03:59

“#define”和内联的行为相同吗?

不,它们不一样!

宏和内联函数之间存在许多差异。

- 求值次数

作为参数传递给内联函数的表达式将求值一次。

在某些情况下,作为参数传递给宏的表达式可以被多次求值。
每次在宏中使用参数时,都会对该参数进行求值。

代码示例:

#define max(a,b) (a>b?a:b)

int main()
{

  int a = 0;
  int b = 1;

  int c = max(a++, b++);

  cout << a << endl << b << endl;
  return 0;

}

本意可能是打印 1 和 2,但宏扩展为:

int c = a++ > b++ ? a++ : b++;

b 递增两次,程序打印 1 和 3。

< em>- 谁评估它们

内联函数由编译器评估,而宏由预编译器在预编译时评估。

- 类型检查

内联函数遵循对普通函数强制执行的所有类型安全协议。
检查参数类型,并正确执行必要的转换。
编译器在将内联函数放入符号表之前执行返回类型检查、函数签名。
它们可以被重载,以便对正确类型的数据执行正确类型的操作。

与内联函数相比,宏更容易出错。参数没有类型化(宏适用于算术类型的任何对象)。
编译期间不进行错误检查。

代码示例:

#define MAX(a, b) ((a < b) ? b : a)

int main( void)
{
   cout << "Maximum of 10 and 20 is " << MAX("20", "10") << endl;
   return 0;
}

可以将字符串传递给执行一些整数算术的宏,并且宏不会抱怨!

- 建议还是命令?

内联只是给编译器的建议。是否内联扩展函数由编译器决定。

宏将始终被扩展。

- 调试怎么样?

内联函数的调试很容易,因为您可以在内联函数定义处放置断点,然后单步执行到方法中进行调试。

宏不能用于调试,因为它们在预编译时扩展。

Do “#define” and inline behave the same?

No they dont!

There are a number of differences between a macro and a inline function.

- No of times of Evaluation

Expressions passed as arguments to inline functions are evaluated once.

In some cases, expressions passed as arguments to macros can be evaluated more than once.
Every time you use an argument in a macro, that argument is evaluated.

A Code sample:

#define max(a,b) (a>b?a:b)

int main()
{

  int a = 0;
  int b = 1;

  int c = max(a++, b++);

  cout << a << endl << b << endl;
  return 0;

}

The intention probably was to print 1 and 2, but macro expands to:

int c = a++ > b++ ? a++ : b++;

b gets incremented twice, and the program prints 1 and 3.

- Who evaluates them

Inline functions are evaluated by the compiler while Macros are evaluated at pre-compilation by precompiler.

- Type checking

Inline functions follow all the protocols of type safety enforced on normal functions.
Argument types are checked, and necessary conversions are performed correctly.
The compiler performs return type checking, function signature before putting inline function into symbol table.
They can be overloaded to perform the right kind of operation for the right kind of data.

Macros are more error prone as compared to inline functions. the The parameters are not typed (the macro works for any objects of arithmetic type).
No error checking is done during compilation.

A Code Sample:

#define MAX(a, b) ((a < b) ? b : a)

int main( void)
{
   cout << "Maximum of 10 and 20 is " << MAX("20", "10") << endl;
   return 0;
}

One can pass strings to a macro that does some integer arithmetic and a macro won't complain!

- Suggestion or Command?

Inline is just a suggestion to the compiler. It is the compiler’s decision whether to expand the function inline or not.

Macros will always be expanded.

- How about Debugging?

Inline functions can be debugged easily because you can put a break point at the inline function definition and step into the method for debugging step by step.

Macros can not be used for debugging as they are expanded at pre-compile time.

一瞬间的火花 2024-11-25 11:03:59

首先,您几乎应该假设所有常量表达式都是在编译时计算的,因此当您运行程序时,乘法永远不会被执行。

其次,您不能依赖 inline 产生任何效果,它只是对编译器的提示,而不是要求。

但即使函数不是内联的,表达式也不会被计算两次,因为参数传递要求它在函数体运行之前被计算。

First, you should pretty much assume that all constant expressions are evaluated at compile-time, so that multiplication never survives to be executed when you run the program.

Second, you can't depend on inline having any effect at all, it's just a hint to the compiler, not a requirement.

But even if the function is not inlined, the expression would not be evaluated twice since argument passing requires it to be evaluated before the body of the function runs.

我早已燃尽 2024-11-25 11:03:59

#define 是简单的文本替换,因此(正如您所注意到的)您可能需要小心括号等。内联参数会正常解析。

存在与条件有关的相关问题

#defines are simple textual substitutions, so (as you noticed) you may need to be careful with parentheses, etc. inline parameters are parsed normally.

There's a related issue with respect to conditions.

失退 2024-11-25 11:03:59

名义上,函数参数 160*2 仅计算一次,然后将结果用在函数体中,而宏则计算 160*2 两次。如果参数表达式有副作用,那么你可以看到这个[*]:ROUND_DOWN(printf("hi!\n"), 1); vs RoundDown(printf("hi !\n"), 1);

实际上,无论函数内联还是宏展开,都只是表达式中的整数运算,没有副作用。优化编译器可以计算出整个宏/函数调用的结果,并将答案粘贴在发出的代码中。因此,您可能会发现您的宏和内联函数会导致执行完全相同的代码,因此 int a = ROUND_DOWN(160*2, 32);int a = RoundDown( 160*2, 32); 可能都与 int a = 320; 相同。

在没有副作用的情况下,优化还可以存储和重用中间结果。因此,int c = ROUND_DONW(a*2, b);最终可能会发出看起来像您编写的代码:

int tmp = a*2;
int c = tmp - tmp % b;

请注意,是否真正内联函数是由编译器基于以下内容做出的决定 :根据自己的优化规则。这些规则可能会考虑函数是否被标记为内联,但很可能不会,除非您使用编译器选项强制内联或其他方式。

因此,假设有一个像样的编译器,就没有理由为此使用宏 - 特别是对于您的宏,您只是乞求有人来写:

int a = ROUND_DOWN(321, 32) * 2;

然后浪费几分钟想知道为什么结果是 319。

[*]尽管不要得意忘形 - 对于某些具有副作用的表达式,例如 i++(其中 i 是整数),由于缺少序列点,宏具有未定义的行为。

Nominally, the function argument 160*2 is evaluated exactly once, and the result is then used in the body of the function, whereas the macro evaluates 160*2 twice. If the argument expression has side-effects, then you can see this[*]: ROUND_DOWN(printf("hi!\n"), 1); vs RoundDown(printf("hi!\n"), 1);

In practice, whether the function is inlined or the macro expanded, it's just integer arithmetic in the expression, with no side-effects. An optimizing compiler can work out the result of the whole macro/function call, and just stick the answer in the emitted code. So you might find that your macro and your inline function result in exactly the same code being executed, and so int a = ROUND_DOWN(160*2, 32); and int a = RoundDown(160*2, 32); might both be the same as int a = 320;.

Where there are no side-effects, optimization can also store and re-use intermediate results. So int c = ROUND_DONW(a*2, b); might end up emitting code that looks as though you've written:

int tmp = a*2;
int c = tmp - tmp % b;

Note that whether to actually inline a function is a decision made by the compiler based on its own optimization rules. Those rules might take account of whether the function is marked inline or not, but quite likely don't unless you're using compiler options to force inlining or whatever.

So, assuming a decent compiler there's no reason to use a macro for this - for your macro in particular you're just begging for someone to come along and write:

int a = ROUND_DOWN(321, 32) * 2;

and then waste a few minutes wondering why the result is 319.

[*] Although don't get carried away - for some expressions with side-effects, for example i++ where i is an integer, the macro has undefined behavior due to lack of sequence points.

舞袖。长 2024-11-25 11:03:59

在您给出的常量示例中,在任何合理的编译器上,两个版本都会在编译时计算常量。

假设您实际上是在询问传入变量的情况,我希望编译器的优化器在这两种情况下生成相同的代码(如果保存结果更有效,它就不会执行两次乘法。最后,内联函数确实为编译器提供了进行实际函数调用的选项(如果它可以提高性能)

最后请注意,我不会担心这样的微优化,因为 99% 它不会。影响影响程序的性能 - I/O 将成为您的瓶颈。

Well in the example you've given with constants, on any reasonable compiler both versions will compute the constant at compile time.

Assuming you're actually asking about cases where variables are passed in, I would expect the compiler's optimizer to generate the same code in both cases (it wouldn't do the multiplication twice if it's more efficient to save off the result. Finally, the inline function does give the compiler the option to make an actual function call if it would improve performance.

Finally note that I wouldn't worry about micro-optimizations like this because 99% it's just going to have no effect on the performance of your program - I/O will be your bottleneck.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文