__attribute __((malloc))vs限制

时间:2018-12-06 13:15:58

标签: c gcc malloc restrict

为什么gcc需要__attribute__((__malloc__))?通过声明malloc(和类似的函数)为返回restrict ed指针(void *restrict malloc(size_t))来传达相同的信息吗?

似乎该方法会更好,因为除了不需要非标准功能外,它还允许人们通过指针(int malloc_by_arg(void *restrict*retval, size_t size);)将其应用于“返回”功能。

2 个答案:

答案 0 :(得分:0)

即使非常相似,当添加public IActionResult Update([Bind(Include="Id,Name")]Employee model)restrict时,相同的函数也会产生不同的优化。考虑以下示例(包含here作为__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 process\n");  
    return 0;
}

正如我们所期望的,具有malloc属性的代码(没有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; } )的优化效果更好。让我只列出不同之处:

没有属性:

-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具有不同的行为来优化代码,即使它们的定义非常相似。考虑到编译器通过不同的方式实现了不同的优化,这使我认为没有必要“合并”它们。即使当两者在同一tiem中使用时,生成的代码也不会比仅使用其中一个(__attribute__((__malloc__))restrict(视情况而定))的最优化代码更好。因此,程序员可以选择根据自己的代码来确定哪个更适合。

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

答案 1 :(得分: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