为什么gcc需要__attribute__((__malloc__))
?通过声明malloc
(和类似的函数)为返回restrict
ed指针(void *restrict malloc(size_t)
)来传达相同的信息吗?
似乎该方法会更好,因为除了不需要非标准功能外,它还允许人们通过指针(int malloc_by_arg(void *restrict*retval, size_t size);
)将其应用于“返回”功能。
答案 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