__attribute__((__malloc__)) 与限制

问题描述 投票:0回答:2

为什么海湾合作委员会需要

__attribute__((__malloc__))
?难道不应该通过声明
malloc
(和类似的函数)作为返回
restrict
ed 指针(
void *restrict malloc(size_t)
)来传达相同的信息吗?

这种方法似乎会更好,因为除了不需要非标准功能之外,它还允许将其应用于通过指针“返回”的函数(

int malloc_by_arg(void *restrict*retval, size_t size);
)。

c gcc malloc restrict
2个回答
1
投票

即使非常相似,当添加

restrict
__attribute__((malloc))
时,相同的函数会产生不同的优化。考虑这个例子(包括here作为
__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 process\n");  
    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 process\n");  
    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 process\n");  
    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/calloc 的函数,使用

__attribute__((__malloc__))
看起来比
restrict
更有用。

__attribute__((__malloc__))
restrict
有不同的行为来优化代码,即使它们的定义非常相似。这让我认为没有必要“合并”它们,因为编译器通过不同的方式实现不同的优化。即使同时使用两者,生成的代码也不会比仅使用其中之一的最优化代码更优化(
__attribute__((__malloc__))
restrict
,取决于情况)。程序员的选择也是如此,根据他/她的代码知道哪一个更适合。

为什么

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


0
投票

在我的测试中,即使基于没有属性的函数,它也可以通过命令优化代码:~/gcc11.1.0-install/bin/aarch64-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
© www.soinside.com 2019 - 2024. All rights reserved.