Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/5.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_Macros_Inline - Fatal编程技术网

C++ 内联函数与预处理器宏

C++ 内联函数与预处理器宏,c++,c,macros,inline,C++,C,Macros,Inline,内联函数与预处理器宏有何不同?关键区别在于类型检查。编译器将检查作为输入值传递的内容是否属于可以传递到函数中的类型。预处理器宏不是这样的-它们在任何类型检查之前都会展开,这会导致严重且难以检测的错误 列出了其他几个不太明显的要点。内联函数在语法上的行为与普通函数一样,提供类型安全性和函数局部变量的作用域,如果是方法,则提供对类成员的访问。 此外,在调用内联方法时,必须遵守私有/受保护的限制。内联函数将维护值语义,而预处理器宏仅复制语法。如果多次使用参数,预处理器宏可能会出现非常微妙的错误,例如,

内联函数与预处理器宏有何不同?

关键区别在于类型检查。编译器将检查作为输入值传递的内容是否属于可以传递到函数中的类型。预处理器宏不是这样的-它们在任何类型检查之前都会展开,这会导致严重且难以检测的错误


列出了其他几个不太明显的要点。

内联函数在语法上的行为与普通函数一样,提供类型安全性和函数局部变量的作用域,如果是方法,则提供对类成员的访问。
此外,在调用内联方法时,必须遵守私有/受保护的限制。

内联函数将维护值语义,而预处理器宏仅复制语法。如果多次使用参数,预处理器宏可能会出现非常微妙的错误,例如,如果参数包含像i++这样的变异,那么执行两次是相当令人惊讶的。内联函数不会有这个问题。

预处理器宏只是应用于代码的替换模式。它们几乎可以在代码中的任何地方使用,因为在任何编译开始之前,它们都会被它们的扩展替换

内联函数是其主体直接注入其调用站点的实际函数。它们只能在函数调用合适的情况下使用

现在,关于在类似函数的上下文中使用宏与内联函数,请注意:

宏不是类型安全的,可以扩展,不管它们是否语法正确-编译阶段将报告由宏扩展问题导致的错误。 宏可以在您不期望的环境中使用,从而导致问题 宏更灵活,因为它们可以扩展其他宏,而内联函数不一定这样做。 宏会因其扩展而产生副作用,因为输入表达式会复制到模式中出现的任何位置。
内联函数并不总是保证内联的——有些编译器只在发布版本中,或者专门配置为内联时才这样做。此外,在某些情况下,可能无法进行内联。 内联函数可以为变量(特别是静态变量)提供作用域,预处理器宏只能在代码块{…}中这样做,而静态变量的行为方式不会完全相同。
宏正在忽略名称空间。首先,预处理器宏只是在编译之前复制粘贴到代码中。因此,没有类型检查,可能会出现一些副作用

例如,如果要比较两个值:

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

在GCC中,我不确定是否还有其他函数,内联声明函数只是对编译器的一个提示。在一天结束时,编译器仍然要决定在调用函数时是否包含函数体

内嵌函数和预处理器宏之间的差异相对较大。预处理器宏只是一天结束时的文本替换。您放弃了编译器对参数和返回类型执行类型检查的许多功能。如果传递到函数中的表达式有副作用,那么参数的计算就大不相同了。调试过程将非常有趣。函数和宏的使用位置存在细微差别。例如,如果我有:

#define MACRO_FUNC(X) ...
其中,宏_FUNC显然定义了函数体。需要特别小心,以便在任何情况下都能正确运行函数,例如,写得不好的宏_FUNC会导致错误

if(MACRO_FUNC(y)) {
 ...body
}

正常函数可以毫无问题地使用。

要给已经给出的函数添加另一个区别:您不能在调试器中单步执行定义,但可以单步执行内联函数。

从编码的角度来看,内联函数就像一个函数。因此,内联函数和宏之间的差异与函数和宏之间的差异相同

从编译的角度来看,内联函数类似于宏。它直接注入到代码中,而不是调用


一般来说,您应该考虑内联函数是正则函数,并将一些小的优化混合进去。和大多数优化一样,由编译器决定是否真正应用它。由于各种原因,编译器通常乐于忽略程序员内联函数的任何尝试。

内联函数类似于宏,因为函数代码在编译时调用时展开,内联函数由编译器解析,而宏由预处理器展开。因此,有几个重要的区别:

内联函数遵循对正常函数强制执行的所有类型安全协议。 内联函数是u指定的 使用与任何其他函数相同的语法,只是它们在函数声明中包含内联关键字。 作为参数传递给内联函数的表达式只计算一次。 在某些情况下,作为参数传递给宏的表达式可以多次求值。

宏在预编译时展开,您不能使用它们进行调试,但可以使用内联函数


)

如果内联函数中存在任何迭代或递归语句,则内联函数将充当函数调用,以防止重复执行指令。这对保存程序的整体内存非常有帮助

内联函数由编译器展开,而宏则由预处理器展开,这仅仅是文本替换

在宏调用期间不进行类型检查,而在函数调用期间进行类型检查

由于重新评估参数和操作顺序,在宏扩展期间可能会出现不期望的结果和低效。比如说

inline int max( int a, int b) { return ((a<b)?b:a); }
#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);
会导致

int i = 5, j = ((i++)>(0) ? (i++) : (0));
宏参数在宏展开之前不求值

#define MUL(a, b) a*b
int main()
{
  // The macro is expended as 2 + 3 * 3 + 5, not as 5*8
  printf("%d", MUL(2+3, 3+5));
 return 0;
}
// Output: 16`
在宏中不能使用return关键字来返回值,就像在函数中一样

内联函数可以重载

传递给宏的令牌可以使用称为令牌粘贴运算符的运算符连接

宏通常用于代码重用,其中as内联函数用于消除函数调用期间的时间开销,避免跳转到子例程

宏通常比函数快,因为它们不涉及实际的函数调用开销

宏的一些缺点: 没有类型检查。调试困难,因为它们会导致简单的替换。宏没有名称空间,所以一段代码中的宏可能会影响另一段代码。宏可能会产生副作用,如上面的示例所示


宏通常是一行。但是,它们可以由多行组成。函数中没有此类约束。

要了解宏函数和内联函数之间的区别,首先我们应该知道它们到底是什么以及何时使用它们

职能:

函数调用具有与之相关的开销,因为在函数完成执行后,它必须知道返回的位置,并且还需要将值存储在堆栈内存中

对于小型应用程序来说,这不会是一个问题,但让我们以金融应用程序为例,在金融应用程序中,每秒发生数千次事务,我们不能使用函数调用

宏:

宏在预处理阶段工作,即在此阶段,用关键字编写的语句将替换为内容,即 int结果=平方x*x

但是宏有与之相关的bug

#define Square(x) x*x
int main() {
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}
这里的输出是11而不是36

内联函数:

产出36

Inline关键字请求编译器用函数体替换函数调用,这里的输出是正确的,因为它首先计算表达式,然后传递。它减少了函数调用开销,因为不需要存储返回地址,函数参数不需要堆栈内存

宏和内联函数之间的比较:

宏通过替换工作,而在内联函数中,函数调用被替换为主体。 宏由于替换而容易出错,而内联函数则可以安全使用。 宏没有地址,而内联函数有地址。 宏很难与多行代码一起使用,而内联函数则不然。 在C++宏中,不能使用成员函数,而内联函数可以使用。 结论:

内联函数有时比宏更有用,因为它改进了 性能和使用安全,并减少了函数调用开销。 这只是对编译器的请求,某些函数不会内联,如:

大功能 具有太多条件参数的函数 递归代码和循环代码等。
这是一件好事,因为这是编译器认为最好以另一种方式执行操作的时间。

的答案包含一些与您的问题相关的信息。本页有一个很好的解释:内联函数并不总是保证内联的:因为编译器不会内联,如果这样做会生成较慢的代码等。编译器会很多分析工程师不能做正确的事情。我相信递归函数是大多数编译器忽略内联的另一个例子。在这种情况下,C与C++相比有什么重要的区别吗?例如,当您为GCC-O2/-O3等最大速度构建时,编译器将选择内联许多函数,但当您为最小大小构建时,Os if通常只内联调用一次或非常小的函数。机智
宏不存在这样的选择。宏不能用访问标识符来覆盖,比如私有的或受保护的,而内联函数是可能的。只要添加到示例中,除了副作用之外,宏还可以引入额外的工作负载,考虑Max FiBoAcCi100,factorial10000较大的一个会被计算两次:每个人都在谈论类型检查,但你提供了一个真实的例子,这就是为什么我支持这个答案。你从定义2_Nn 2中得到了多大的乐趣,正如一句话:宏可以用括号固定为同一个数字求值。但是,它仍然容易出错,因为在实现过程中需要考虑绝对的哑替代和所有情况。
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
#define Square(x) x*x
int main() {
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}
inline int Square(int x) {
    return x * x;
}

int main() {
    using namespace std;
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}