嗨,我有以下的设计,我想知道一般来说,C编译器(gcc或clang)是否会试图在编译时解析函数指针,或者总是将其保留到运行时。
在测试h中:
typedef struct array_ {
size_t size;
void *array;
size_t (*get_size)(struct array_ *);
} array_t;
static inline size_t
get_size (array_t *A) {
return A->get_size(A);
}
在测试c中:
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
static size_t _get_size (array_t *A) {
return A->size;
}
int main(void)
{
array_t *A = malloc(sizeof(array_t));
A->size = 3;
A->array = (int[]){1,2,3};
A->get_size = _get_size;
printf("%llu\n", A->get_size(A));
printf("%llu\n", get_size(A));
return 0;
}
我的问题是->获取大小(A)是在编译时解析为获取大小(A)还是甚至可能解析为->大小?A->get_size()是否总是比get_size(A)更有效?或者它们是否编译成几乎相同的东西?
我意识到我在问编译器会做什么或不会做什么,这取决于编译器和其他事情(例如优化级别),但总的来说,是有答案,还是仅仅取决于太多事情?
编辑:为了清楚起见,我省略了错误检查。
编辑:“gcc-S”代码我想指针被解引用了。
main:
.LFB4:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl $24, %edi
call malloc
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movq $3, (%rax)
movl $1, -16(%rbp)
movl $2, -12(%rbp)
movl $3, -8(%rbp)
movq -24(%rbp), %rax
leaq -16(%rbp), %rdx
movq %rdx, 8(%rax)
movq -24(%rbp), %rax
movq $_get_size, 16(%rax)
movq -24(%rbp), %rax
movq 16(%rax), %rax
movq -24(%rbp), %rdx
movq %rdx, %rdi
call *%rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -24(%rbp), %rax
movq %rax, %rdi
call get_size
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
最佳答案
下面是CLAN如何在最大优化下实现main
函数
; function prologue
0xa071: pushl %ebp ; save the base pointer
0xa072: movl %esp, %ebp ; setup new base pointer
0xa074: pushl %esi ; save esi register
0xa075: subl $0x14, %esp ; reserve 20 bytes
; compute the address of the format string "%llu\n"
0xa078: calll 0xa07d ; put the PC on the stack
0xa07d: popl %eax ; put the PC into eax
0xa07e: leal 0x6f8e(%eax), %esi ; esi points to the format string
; first call to printf
0xa084: movl %esi, (%esp) ; put the format string on the stack
0xa087: movl $0x3, 0x4(%esp) ; put the precomputed size on the stack
0xa08f: calll 0xc674 ; call printf
; second call to printf
0xa094: movl %esi, (%esp) ; put the format string on the stack
0xa097: movl $0x3, 0x4(%esp) ; put the precomputed size on the stack
0xa09f: calll 0xc674 ; call printf
; function epilogue
0xa0a4: xorl %eax, %eax ; return value is 0
0xa0a6: addl $0x14, %esp ; clean up the stack
0xa0a9: popl %esi ; restore esi register
0xa0aa: popl %ebp ; restore the base pointer
0xa0ab: ret ; done
在最大优化时,CLAN远远超出编译时函数指针的解析。它删除了与结构相关的所有代码。
不必打电话给
malloc
它不会生成任何代码来初始化结构
它预先计算
A->get_size(A)
它预先计算
get_size(A)
因此
main
中的代码本质上被简化为int main(void)
{
printf("%llu\n", 3 );
printf("%llu\n", 3 );
return 0;
}
关于c - 编译时间函数ptr取消引用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27335308/