html未知错误,百度网盘遇到未知错误(示例代码)

内联函数的不足

除了通常使用内联扩展可能带来的问题,作为一种编程语言特性的内联函数也可能并没有看起来那么有效,原因如下:

通常,设计编译器的程序设计者比大多数的程序设计者更清楚对于一个特定的函数是否合适进行内联扩展;一些情况下,对于程序员指定的某些内联函数,编译器可能更倾向于不使用内联甚至根本无法完成内联。

对于一些开发中的函数,它们可能从原来的不适合内联扩展变得适合或者倒过来。尽管内联函数或者非内联函数的转换易于宏的转换,但增加的维护开支还是使得它的优点显得更不突出了。

对于基于C的编译系统,内联函数的使用可能大大增加编译时间,因为每个调用该函数的地方都需要替换成函数体,代码量的增加也同时带来了潜在的编译时间的增加。

内联函数是在函数原型的前面加上inline (内联)限定符。例如:

b61daae6cc1d445986afd154e6ec1504.jpg

https://zh.wikipedia.org/wiki/内联函数

在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展);也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。但在选择使用内联函数时,必须在程序占用空间和程序执行效率之间进行权衡,因为过多的比较复杂的函数进行内联扩展将带来很大的存储资源开支。另外还需要特别注意的是对递归函数的内联扩展可能引起部分编译器的无穷编译。

设计内联函数的动机

内联扩展是一种特别的用于消除调用函数时所造成的固有的时间消耗方法。一般用于能够快速执行的函数,因为在这种情况下函数调用的时间消耗显得更为突出。这种方法对于很小的函数也有空间上的益处,并且它也使得一些其他的优化成为可能。

没有了内联函式,程式员难以控制哪些函数内联哪些不内联;由编译器自行决定是否内联。加上这种控制维度准许特定于应用的知识,诸如执行函式的频繁程度,被利用于选择哪些函数要内联。

此外,在一些语言中,内联函数与编译模型联系紧密:如在C++中,有必要在每个使用它的模块中定义一个内联函数;与之相对应的,普通函数必须定义在单个模块中。这使得模块编译独立于其他的模块。

与宏的比较

通常,在C语言中,内联展开的功能由带参宏(Macros)在源码级实现。内联提供了几个更好的方法:

宏调用并不执行类型检查,甚至连正常参数也不检查,但是函数调用却要检查。

C语言的宏使用的是文本替换,可能导致无法预料的后果,因为需要重新计算参数和操作顺序。

在宏中的编译错误很难发现,因为它们引用的是扩展的代码,而不是程序员键入的。

许多结构体使用宏或者使用不同的语法来表达很难理解。内联函数使用与普通函数相同的语言,可以随意的内联和不内联。

内联代码的调试信息通常比扩展的宏代码更有用。

语言支持

C++,C99. C11和GNU C都支持内联函数,然而1989 ANSI C,这个最被广泛使用的C标准却不支持。在Ada中,关键字“pragma”可以用来声明内联。其他的大部分编程语言,包括Java和函数式语言,不支持内联函数,但他们的编译器常常进行强制性的内联扩展。不同的编译器在内联扩展上有处理不同复杂程度函数的能力。主流的C++编译器如Visual C++和GCC提供了一个选项来自动内联任何一个合适的函数,即使它们没有被声明为内联函数。

对于C++,inline与extern inline同义:内联函数在各个编译单元都可能会生成一份,要求各处定义完全一致。内联函数在C++中的写法如下:

inline int max (int a, int b)

{

if (a > b)

return a;

else

return b;

}

a = max (x, y); // 等价于 "a = (x > y ? x : y);"

对于C99,inline为编译单元内部可见,extern inline为编译单元外部也可见。

内联函数的不足

除了通常使用内联扩展可能带来的问题,作为一种编程语言特性的内联函数也可能并没有看起来那么有效,原因如下:

通常,编译器比程序设计者更清楚对于一个特定的函数是否合适进行内联扩展;一些情况下,对于程序员指定的某些内联函数,编译器可能更倾向于不使用内联甚至根本无法完成内联。

对于一些开发中的函数,它们可能从原来的不适合内联扩展变得适合或者倒过来。尽管内联函数或者非内联函数的转换易于宏的转换,但增加的维护开支还是使得它的优点显得更不突出了。

对于基于C的编译系统,内联函数的使用可能大大增加编译时间,因为每个调用该函数的地方都需要替换成函数体,代码量的增加也同时带来了潜在的编译时间的增加。

参见

In the C and C++ programming languages, an inline function is one qualified with the keyword inline; this serves two purposes. Firstly, it serves as a compiler directive that suggests (but does not require) that the compiler substitute the body of the function inline by performing inline expansion, i.e. by inserting the function code at the address of each function call, thereby saving the overhead of a function call. In this respect it is analogous to the register storage class specifier, which similarly provides an optimization hint.inline is to change linkage behavior; the details of this are complicated. This is necessary due to the C/C++ separate compilation + linkage model, specifically because the definition (body) of the function must be duplicated in all translation units where it is used, to allow inlining during compiling, which, if the function has external linkage, causes a collision during linking (it violates uniqueness of external symbols). C and C++ (and dialects such as GNU C and Visual C++) resolve this in different ways.

Example

An inline function can be written in C or C++ like this:

inline void swap(int *m, int *n)

{

int tmp = *m;

*m = *n;

*n = tmp;

}

Then, a statement such as the following:

swap(&x, &y);

may be translated into (if the compiler decides to do the inlining, which typically requires optimization to be enabled):

int tmp = x;

x = y;

y = tmp;

When implementing a sorting algorithm doing lots of swaps, this can increase the execution speed.

Standard support

C++ and C99, but not its predecessors K&R C and C89, have support for inline functions, though with different semantics. In both cases, inline does not force inlining; the compiler is free to choose not to inline the function at all, or only in some cases. Different compilers vary in how complex a function they can manage to inline. Mainstream C++ compilers like Microsoft Visual C++ and GCC support an option that lets the compilers automatically inline any suitable function, even those not marked as inline functions. However, simply omitting the inline keyword to let the compiler make all inlining decisions is not possible, since the linker will then complain about duplicate definitions in different translation units. This is because inline not only gives the compiler a hint that the function should be inlined, it also has an effect on whether the compiler will generate a callable out-of-line copy of the function (see storage classes of inline functions).

Nonstandard extensions

GNU C, as part of the dialect gnu89 that it offers, has support for inline as an extension to C89. However, the semantics differ from both those of C++ and C99. armcc in C90 mode also offers inline as a non-standard extension, with semantics different from gnu89 and C99.

Some implementations provide a means by which to force the compiler to inline a function, usually by means of implementation-specific declaration specifiers:

Microsoft Visual C++: __forceinline

gcc or clang: __attribute__((always_inline)) or __attribute__((__always_inline__)), the latter of which is useful to avoid a conflict with a user-defined macro named always_inline.

Indiscriminate uses of that can result in larger code (bloated executable file), minimal or no performance gain, and in some cases even a loss in performance. Moreover, the compiler cannot inline the function in all circumstances, even when inlining is forced; in this case both gcc and Visual C++ generate warnings.

Forcing inlining is useful if

inline is not respected by the compiler (ignored by compiler cost/benefit analyzer), and

inlining results in a necessary performance boost

For code portability, the following preprocessor directives may be used:

#ifdef _MSC_VER

#define forceinline __forceinline

#elif defined(__GNUC__)

#define forceinline inline __attribute__((__always_inline__))

#elif defined(__CLANG__)

#if __has_attribute(__always_inline__)

#define forceinline inline __attribute__((__always_inline__))

#else

#define forceinline inline

#endif

#else

#define forceinline inline

#endif

Storage classes of inline functions

static inline has the same effects in all C dialects and C++. It will emit a locally visible (out-of-line copy of the) function if required.

Regardless of the storage class, the compiler can ignore the inline qualifier and generate a function call in all C dialects and C++.

The effect of the storage class extern when applied or not applied to inline functions differs between the C dialects

C99

In C99, a function defined inline will never, and a function defined extern inline will always, emit an externally visible function. Unlike in C++, there is no way to ask for an externally visible function shared among translation units to be emitted only if required.

If inline declarations are mixed with extern inline declarations or with unqualified declarations (ie., without inline qualifier or storage class), the translation unit must contain a definition (no matter whether unqualified, inline, or extern inline) and an externally visible function will be emitted for it.

A function defined inline requires exactly one function with that name somewhere else in the program which is either defined extern inline or without qualifier. If more than one such definition is provided in the whole program, the linker will complain about duplicate symbols. If, however, it is lacking, the linker does not necessarily complain, because, if all uses could be inlined, it is not needed. But it may complain, since the compiler can always ignore the inline qualifier and generate calls to the function instead, as typically happens if the code is compiled without optimization. (This may be the desired behavior, if the function is supposed to be inlined everywhere by all means, and an error should be generated if it is not.) A convenient way is to define the inline functions in header files and create one .c file per function, containing an extern inline declaration for it and including the respective header file with the definition. It does not matter whether the declaration is before or after the include.

To prevent unreachable code from being added to the final executable if all uses of a function were inlined, it is advisedextern inline function into a static library file, typically with ar rcs, then link against that library instead of the individual object files. That causes only those object files to be linked that are actually needed, in contrast to linking the object files directly, which causes them to be always included in the executable. However, the library file must be specified after all the other object files on the linker command line, since calls from object files specified after the library file to the functions will not be considered by the linker. Calls from inline functions to other inline functions will be resolved by the linker automatically (the s option in ar rcs ensures this).

An alternative solution is to use link time optimization instead of a library. gcc provides the flag -Wl,--gc-sections to omit sections in which all functions are unused. This will be the case for object files containing the code of a single unused extern inline function. However, it also removes any and all other unused sections from all other object files, not just those related to unused extern inline functions. (It may be desired to link functions into the executable that are to be called by the programmer from the debugger rather than by the program itself, eg., for examining the internal state of the program.) With this approach, it is also possible to use a single .c file with all extern inline functions instead of one .c file per function. Then the file has to be compiled with -fdata-sections -ffunction-sections. However, the gcc manual page warns about that, saying "Only use these options when there are significant benefits from doing so."

Some recommend an entirely different approach, which is to define functions as static inline instead of inline in header files.static inline in a header file will yield different values in different translation units. Therefore, static inline functions should only be used if they are used in only one translation unit, which means that they should only go to the respective .c file, not to a header file.

gnu89

gnu89 semantics of inline and extern inline are essentially the exact opposite of those in C99,extern inline function as an unqualified function, while C99 inline does not.extern inline without redefinition is like C99 inline, and gnu89 inline is like C99 extern inline; in other words, in gnu89, a function defined inline will always and a function defined extern inline will never emit an externally visible function. The rationale for this is that it matches variables, for which storage will never be reserved if defined as extern and always if defined without. The rationale for C99, in contrast, is that it would be astonishing if using inline would have a side-effect—to always emit a non-inlined version of the function—that is contrary to what its name suggests.

The remarks for C99 about the need to provide exactly one externally visible function instance for inlined functions and about the resulting problem with unreachable code apply mutatis mutandis to gnu89 as well.

gcc up to and including version 4.2 used gnu89 inline semantics even when -std=c99 was explicitly specified.inline semantics by default. To use gnu89 semantics instead, they have to be enabled explicitly, either with -std=gnu89 or, to only affect inlining, -fgnu89-inline, or by adding the gnu_inline attribute to all inline declarations. To ensure C99 semantics, either -std=c99, -std=c11, -std=gnu99 or -std=gnu11 (without -fgnu89-inline) can be used.

C++

In C++, a function defined inline will, if required, emit a function shared among translation units, typically by putting it into the common section of the object file for which it is needed. The function must have the same definition everywhere, always with the inline qualifier. In C++, extern inline is the same as inline. The rationale for the C++ approach is that it is the most convenient way for the programmer, since no special precautions for elimination of unreachable code must be taken and, like for ordinary functions, it makes no difference whether extern is specified or not.

The inline qualifier is automatically added to a function defined as part of a class definition.

armcc

armcc in C90 mode provides extern inline and inline semantics that are the same as in C++: Such definitions will emit a function shared among translation units if required. In C99 mode, extern inline always emits a function, but like in C++, it will be shared among translation units. Thus, the same function can be defined extern inline in different translation units.extern definitions of uninitialized global variables.

Restrictions

Taking the address of an inline function requires code for a non-inlined copy of that function to be emitted in any case.

In C99, an inline or extern inline function must not access static global variables or define non-const static local variables. const static local variables may or may not be different objects in different translation units, depending on whether the function was inlined or whether a call was made. Only static inline definitions can reference identifiers with internal linkage without restrictions; those will be different objects in each translation unit. In C++, both const and non-const static locals are allowed and they refer to the same object in all translation units.

gcc cannot inline functions if

they are variadic,

use alloca

use computed goto

use nonlocal goto

use setjmp

use __builtin_longjmp

use __builtin_return, or

use __builtin_apply_args

Based on Microsoft Specifications at MSDN, MS Visual C++ cannot inline (not even with __forceinline), if

The function or its caller is compiled with /Ob0 (the default option for debug builds).

The function and the caller use different types of exception handling (C++ exception handling in one, structured exception handling in the other).

The function uses inline assembly, unless compiled with /Og, /Ox, /O1, or /O2.

The function is recursive and not accompanied by #pragma inline_recursion(on). With the pragma, recursive functions are inlined to a default depth of 16 calls. To reduce the inlining depth, use inline_depth pragma.

The function is virtual and is called virtually. Direct calls to virtual functions can be inlined.

The program takes the address of the function and the call is made via the pointer to the function. Direct calls to functions that have had their address taken can be inlined.

The function is also marked with the naked __declspec modifier.

Problems

Besides the problems with inline expansion in general, inline functions as a language feature may not be as valuable as they appear, for a number of reasons:

Often, a compiler is in a better position than a human to decide whether a particular function should be inlined. Sometimes the compiler may not be able to inline as many functions as the programmer indicates.

An important point to note is that the code (of the inline function) gets exposed to its client (the calling function).

As functions evolve, they may become suitable for inlining where they were not before, or no longer suitable for inlining where they were before. While inlining or un-inlining a function is easier than converting to and from macros, it still requires extra maintenance which typically yields relatively little benefit.

Inline functions used in proliferation in native C-based compilation systems can increase compilation time, since the intermediate representation of their bodies is copied into each call site.

The specification of inline in C99 requires exactly one external definition of the function, if it is used somewhere. If such a definition wasn\'t provided by the programmer, that can easily lead to linker errors. This can happen with optimization turned off, which typically prevents inlining. Adding the definitions, on the other hand, can cause unreachable code if the programmer does not carefully avoid it, by putting them in a library for linking, using link time optimization, or static inline.

In C++, it is necessary to define an inline function in every module (translation unit) that uses it, whereas an ordinary function must be defined in only a single module. Otherwise it would not be possible to compile a single module independently of all other modules. Depending on the compiler, this may cause each respective object file to contain a copy of the function\'s code, for each module with some use that could not be inlined.

In embedded software, oftentimes certain functions need to be placed in certain code sections by use of special compiler instructions such as "pragma" statements. Sometimes, a function in one memory segment might need to call a function in another memory segment, and if inlining of the called function occurs, then the code of the called function might end up in a segment where it shouldn\'t be. For example, high-performance memory segments may be very limited in code space, and if a function belonging in such a space calls another large function that is not meant to be in the high-performance section and the called function gets inappropriately inlined, then this might cause the high-performance memory segment to run out of code space. For this reason, sometimes it is necessary to ensure that functions do not become inlined.

Quotes

"A function declaration [ . . . ] with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected."— ISO/IEC 14882:2011, the current C++ standard, section 7.1.2"A function declared with an inline function specifier is an inline function. [ . . . ] Making a function an inline function suggests that calls to the function be as fast as possible. The extent to which such suggestions are effective is implementation-defined (footnote: For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration.)"[ . . . ] An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition."— ISO 9899:1999(E), the C99 standard, section 6.7.4

See also

References

https://en.wikipedia.org/wiki/Inline_function

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值