C语言 __attribute__((malloc)) vs restrict



为什么gcc需要__attribute__((__malloc__))?通过声明malloc(和类似的函数(作为返回restrict的指针(void *restrict malloc(size_t)(,同一信息难道不应该是可通信的吗?

这种方法似乎会更好,因为除了不需要非标准特性外,它还允许将其应用于通过指针(int malloc_by_arg(void *restrict*retval, size_t size);("返回"的函数。

即使非常相似,当添加restrict__attribute__((malloc))时,相同的函数也会产生不同的优化效果。考虑这个例子(包括在这里作为__attribute__((malloc))的一个好例子的参考(:

#include <stdlib.h>
#include <stdio.h>
int a;
void* my_malloc(int size)  __attribute__ ((__malloc__))
{
void* p = malloc(size);  
if (!p) {    
printf("my_malloc: out of memory!n");    
exit(1);  
}  
return p;
}
int main() {  
int* x = &a;  
int* p = (int*) my_malloc(sizeof(int));  
*x = 0; 
*p = 1;  
if (*x) printf("This printf statement to be detected as unreachable 
and discarded during compilation processn");  
return 0;
}

这个(没有属性的相同代码(:

void* my_malloc(int size);
int a;
void* my_malloc(int size)
{
void* p = malloc(size);  
if (!p) {    
printf("my_malloc: out of memory!n");    
exit(1);  
}  
return p;
}
int main() {  
int* x = &a;  
int* p = (int*) my_malloc(sizeof(int));  
*x = 0; 
*p = 1;  
if (*x) printf("This printf statement to be detected as unreachable 
and discarded during compilation processn");  
return 0;
}

正如我们所料,带有malloc属性的代码(都有-O3(比没有它的代码优化得更好

无属性:

[...]
call    ___main
movl    $4, (%esp)
call    _malloc
testl   %eax, %eax
je  L9
movl    $0, _a
xorl    %eax, %eax
leave
.cfi_remember_state
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
L9:
.cfi_restore_state
movl    $LC0, (%esp)
call    _puts
movl    $1, (%esp)
call    _exit
.cfi_endproc
[...]

具有属性:

[...]
call    ___main
movl    $4, (%esp)
call    _my_malloc
movl    $0, _a
xorl    %eax, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
[...]

尽管如此,在这种情况下使用restrict是没有价值的,因为它不会优化生成的代码。如果我们修改要与restrict:一起使用的原始代码

void *restrict my_malloc(int size);
int a;
void *restrict my_malloc(int size)
{
void *restrict p = malloc(size);  
if (!p) {    
printf("my_malloc: out of memory!n");    
exit(1);  
}  
return p;
}
int main() {  
int* x = &a;  
int* p = (int*) my_malloc(sizeof(int));  
*x = 0; 
*p = 1;  
if (*x) printf("This printf statement to be detected as unreachable and discarded 
during compilation processn");  
return 0;
}

asm代码与不带malloc属性的生成代码完全相同:

[...]
call    ___main
movl    $4, (%esp)
call    _malloc
testl   %eax, %eax
je  L9
movl    $0, _a
xorl    %eax, %eax
leave
.cfi_remember_state
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
L9:
.cfi_restore_state
movl    $LC0, (%esp)
call    _puts
movl    $1, (%esp)
call    _exit
.cfi_endproc
[...]

因此,对于类似malloc/caloc的函数,__attribute__((__malloc__))的使用看起来比restrict更有用。

__attribute__((__malloc__))restrict具有不同的行为来优化代码,即使它们的定义非常相似。这让我认为"合并"它们是没有意义的,因为编译器通过不同的方式实现了不同的优化。即使两者同时使用,生成的代码也不会比只使用其中一个(__attribute__((__malloc__))restrict,具体取决于情况(的优化程度最高的代码更优化。程序员根据自己的代码选择哪一个更合适也是如此。

为什么__attribute__((__malloc__))不是标准?我不知道,但IMO,从定义的角度来看,这些相似之处和从行为的角度来看的差异无助于以清晰、差异化和通用的方式将两者整合到标准中。

在我的测试中,即使基于没有属性的函数,它也可以通过以下命令优化代码:~/gcc1.1.0-install/bin/arch64-linux-gnu-gcc test2.c-O3-S

main:
.LFB23:
.cfi_startproc
stp     x29, x30, [sp, -16]!
.cfi_def_cfa_offset 16
.cfi_offset 29, -16
.cfi_offset 30, -8
mov     w0, 4
mov     x29, sp
bl      my_malloc
adrp    x1, .LANCHOR0
mov     w0, 0
ldp     x29, x30, [sp], 16
.cfi_restore 30
.cfi_restore 29
.cfi_def_cfa_offset 0
str     wzr, [x1, #:lo12:.LANCHOR0]
ret
.cfi_endproc
.LFE23:
.size   main, .-main

相关内容

  • 没有找到相关文章

最新更新