Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “做”#定义;你的行为也一样吗?_C++_C_C Preprocessor_Inline Functions - Fatal编程技术网

C++ “做”#定义;你的行为也一样吗?

C++ “做”#定义;你的行为也一样吗?,c++,c,c-preprocessor,inline-functions,C++,C,C Preprocessor,Inline Functions,我的一个标题中有一些简短的定义,如下所示: #define ROUND_DOWN(a,b) (a)-(a)%(b) e、 g 但如果我把这个传给它: ROUND_DOWN(160*2, 32); 然后就这样编译了 (160*2)-(160*2)%(32), 这只是更多的处理,因为它做了160*2两次 我想知道内联函数是否以同样的方式运行?e、 g inline int RoundDown(int a, int b) { return (a)-(a)%(b) } 160*2是否会像3

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

#define ROUND_DOWN(a,b)   (a)-(a)%(b)
e、 g

但如果我把这个传给它:

ROUND_DOWN(160*2, 32);
然后就这样编译了

(160*2)-(160*2)%(32), 
这只是更多的处理,因为它做了160*2两次

我想知道内联函数是否以同样的方式运行?e、 g

inline int RoundDown(int a, int b)
{
return (a)-(a)%(b)
}
160*2是否会像320一样存储在“inta”中,然后计算就可以了,或者它的行为是否与define相同

一个更好的例子是调用:

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

首先,您几乎应该假设所有常量表达式都是在编译时求值的,这样在运行程序时乘法就不会继续执行

第二,你不能指望
inline
有任何效果,它只是对编译器的提示,而不是要求


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

通常,函数参数
160*2
只计算一次,然后在函数体中使用结果,而宏计算两次
160*2
。如果参数表达式有副作用,那么您可以看到以下[*]:
四舍五入(printf(“hi!\n”),1)vs
向下取整(printf(“hi!\n”),1)

实际上,无论函数是内联的还是宏扩展的,它都只是表达式中的整数运算,没有任何副作用。优化编译器可以计算出整个宏/函数调用的结果,只需将答案粘贴到发出的代码中即可。因此,您可能会发现宏和内联函数执行的代码完全相同,因此
inta=ROUND_DOWN(160*2,32)
inta=四舍五入(160*2,32)可能与
inta=320相同

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

int tmp = a*2;
int c = tmp - tmp % b;
请注意,是否实际内联函数是编译器根据自己的优化规则做出的决定。这些规则可能会考虑函数是否标记为
inline
,但很可能不会,除非您使用编译器选项强制内联或其他方式

因此,假设有一个像样的编译器,就没有理由使用宏来实现这一点——特别是对于您的宏,您只是请求有人来编写:

int a = ROUND_DOWN(321, 32) * 2;
然后浪费几分钟去想为什么结果是319

[*]尽管不要忘乎所以-对于一些有副作用的表达式,例如
i++
其中
i
是一个整数,但由于缺少序列点,宏具有未定义的行为。

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


关于条件有一个问题。

在你给出的关于常数的例子中,在任何合理的编译器上,两个版本都会在编译时计算常数

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

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

是否“定义”和内联行为相同?

不,他们没有

宏和内联函数之间有许多不同之处

-评估次数

作为参数传递给内联函数的表达式只计算一次

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

代码示例:

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

-谁对他们进行评估

内联函数由编译器计算,而宏由预编译器在预编译时计算

-类型检查

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

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

代码示例:

定义最大值(a,b)((acout
2*向下取整(178,32)
将使事情不再有效。使用
定义向下取整(a,b)((a)-(a)%(b))
(注意额外的括号)。结论:无论如何不会有相同的行为。尝试向下取整(x++,y)
用你的宏看看会发生什么。@Fred:或者不看会发生什么,因为UB会让看不见的恶魔飞出你的鼻子。对不起,我的坏例子,我不做常量计算,我的代码更像是“取整((x+x2)*缩放,平铺宽度);”,如果编译器确实将我的函数视为内联函数,它会计算两次还是存储在参数中?@Kaije:表达式将被计算一次。句号。函数的内容,
inline
与否,与
int a = ROUND_DOWN(321, 32) * 2;
#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;

}
int c = a++ > b++ ? a++ : b++;
#define MAX(a, b) ((a < b) ? b : a)

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