您好我有以下设计,我想知道一般来说C编译器(gcc或clang)是否会在编译时尝试解析函数指针,或者它会一直保留到运行时。
在test.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);
}
在test.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-&gt; get_size(A)在编译时解析为_get_size(A),甚至可能解析为A-&gt;大小? A-> get_size()总是比get_size(A)更有效,还是编译成几乎相同的东西?
我意识到我在询问编译器将会做什么或者不会做什么,这取决于编译器和其他事情(例如优化级别),但一般来说是答案还是只依赖于太多东西了?
编辑:为了清楚起见,我省略了错误检查。
编辑:&#34; gcc -S&#34;码。我认为指针被取消引用了。
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
答案 0 :(得分:4)
由于您刚刚将函数指针分配到使用它的上方一行,因此gcc和clang等优秀的编译器应该足够聪明,可以在编译时解析它。但是一旦你开始在不同文件中的不同函数之间传递指向该结构的指针,它们几乎肯定不会在编译时解决它。
如果您想详细了解编译器,则应该开始查看反汇编列表。
如果你想在你的示例代码中使用这样的语法并有效地编译它,那么C ++就是一种很好的语言。
答案 1 :(得分:3)
以下是clang如何在最大优化时实现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
在最大化优化时,clang远远超出了在编译时解析函数指针的能力。它删除与结构相关的代码的所有。
malloc
A->get_size(A)
get_size(A)
因此main
中的代码基本上缩减为
int main(void)
{
printf("%llu\n", 3 );
printf("%llu\n", 3 );
return 0;
}