C 和内联函数中的独立目标代码
stand alone object code in C and inline functions
当我读到 Inline Functions In C 的 inline
函数时,我看到了这条线:
Sometimes it is necessary for the compiler to emit a stand-alone copy of the object code for a function even though it is an inline function - for instance if it is necessary to take the address of the function, or if it can't be inlined in some particular context, or (perhaps) if optimization has been turned off. (And of course, if you use a compiler that doesn't understand inline, you'll need a stand-alone copy of the object code so that all the calls actually work at all.)
我完全不知道它想说什么,有人可以专门解释一下什么是独立目标代码吗?
如您所知,"inline" 函数被翻译成 "right there." 的机器指令,每次出现新的 "call" 函数时,这些指令都会逐字重复不同的地方——函数实际上不是 "called."(内联函数非常像汇编程序 "macro.")
但是,如果您要求(比如)"the address of" 函数,编译器必须生成它的非内联副本才能为您提供 one"place where it is."
"Object code"一般是指编译器的输出交给链接器,作为生成机器码前的中间步骤。
文中所说的是,如果您出于某种原因获取函数的地址,例如使用指向它的函数指针,则无法内联该函数。因为内联函数没有可以通过函数指针调用的地址。内联函数只是与调用代码链接在一起,实际上没有进行任何函数调用。
这里有一个例子:
#include <stdio.h>
#include <stdlib.h>
extern inline __attribute__((always_inline)) int mul16(int x) {
return x * 16; }
extern inline __attribute__((always_inline)) int mul3(int x) {
return x * 3; }
int main() {
for(int i = 0; i < 10; i ++)
{
int (*ptr)(int) = rand() & 1 ? mul16 : mul3;
printf("Mul2 = %d", mul16(i));
printf(", ptr(i) = %d\n", ptr(i));
}
}
mul16
作为单独的对象存在,也内联在同一代码中。
mul16: <----- object
mov eax, edi
sal eax, 4
ret
mul3:
lea eax, [rdi+rdi*2]
ret
.LC0:
.string "Mul2 = %d"
.LC1:
.string ", ptr(i) = %d\n"
main:
push r12
push rbp
push rbx
mov ebx, 0
mov r12d, OFFSET FLAT:mul16
.L5:
call rand
test al, 1
mov ebp, OFFSET FLAT:mul3
cmovne rbp, r12
mov esi, ebx
sal esi, 4 <-------------- inlined version
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov edi, ebx
call rbp
mov esi, eax
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call printf
add ebx, 1
cmp ebx, 10
jne .L5
mov eax, 0
pop rbx
pop rbp
pop r12
ret
当我读到 Inline Functions In C 的 inline
函数时,我看到了这条线:
Sometimes it is necessary for the compiler to emit a stand-alone copy of the object code for a function even though it is an inline function - for instance if it is necessary to take the address of the function, or if it can't be inlined in some particular context, or (perhaps) if optimization has been turned off. (And of course, if you use a compiler that doesn't understand inline, you'll need a stand-alone copy of the object code so that all the calls actually work at all.)
我完全不知道它想说什么,有人可以专门解释一下什么是独立目标代码吗?
如您所知,"inline" 函数被翻译成 "right there." 的机器指令,每次出现新的 "call" 函数时,这些指令都会逐字重复不同的地方——函数实际上不是 "called."(内联函数非常像汇编程序 "macro.")
但是,如果您要求(比如)"the address of" 函数,编译器必须生成它的非内联副本才能为您提供 one"place where it is."
"Object code"一般是指编译器的输出交给链接器,作为生成机器码前的中间步骤。
文中所说的是,如果您出于某种原因获取函数的地址,例如使用指向它的函数指针,则无法内联该函数。因为内联函数没有可以通过函数指针调用的地址。内联函数只是与调用代码链接在一起,实际上没有进行任何函数调用。
这里有一个例子:
#include <stdio.h>
#include <stdlib.h>
extern inline __attribute__((always_inline)) int mul16(int x) {
return x * 16; }
extern inline __attribute__((always_inline)) int mul3(int x) {
return x * 3; }
int main() {
for(int i = 0; i < 10; i ++)
{
int (*ptr)(int) = rand() & 1 ? mul16 : mul3;
printf("Mul2 = %d", mul16(i));
printf(", ptr(i) = %d\n", ptr(i));
}
}
mul16
作为单独的对象存在,也内联在同一代码中。
mul16: <----- object
mov eax, edi
sal eax, 4
ret
mul3:
lea eax, [rdi+rdi*2]
ret
.LC0:
.string "Mul2 = %d"
.LC1:
.string ", ptr(i) = %d\n"
main:
push r12
push rbp
push rbx
mov ebx, 0
mov r12d, OFFSET FLAT:mul16
.L5:
call rand
test al, 1
mov ebp, OFFSET FLAT:mul3
cmovne rbp, r12
mov esi, ebx
sal esi, 4 <-------------- inlined version
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov edi, ebx
call rbp
mov esi, eax
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call printf
add ebx, 1
cmp ebx, 10
jne .L5
mov eax, 0
pop rbx
pop rbp
pop r12
ret