C 如何判断函数参数是否为立即数?

C 如何判断函数参数是否为立即数?,c,gcc,ld,gnu-assembler,C,Gcc,Ld,Gnu Assembler,我有一个封装内联程序集的内联函数定义。我想选择 不同的内联程序集实现取决于参数是否 是否在构建时已知 我的问题是如何在C代码或内联程序集中询问地址值是否在构建时已知,因此是否适合作为立即值。如果你在想“内置常量”,请提前阅读 这里有一段代码说明了我的意图:。我正试图找到一种方法来实现“即时” 乍一看uuu内置常数u p()似乎正是所需的魔法,只是它不起作用 原因是它不起作用,因为链接器将数组放入内存并为其选择一个地址后(因此它符合内联程序集的即时约束),数组的地址将是已知的,但在链接之前的编译时

我有一个封装内联程序集的内联函数定义。我想选择 不同的内联程序集实现取决于参数是否 是否在构建时已知

我的问题是如何在C代码或内联程序集中询问地址值是否在构建时已知,因此是否适合作为立即值。如果你在想“内置常量”,请提前阅读

这里有一段代码说明了我的意图:。我正试图找到一种方法来实现“即时”

乍一看uuu内置常数u p()似乎正是所需的魔法,只是它不起作用

原因是它不起作用,因为链接器将数组放入内存并为其选择一个地址后(因此它符合内联程序集的即时约束),数组的地址将是已知的,但在链接之前的编译时它是未知的


所以,我想问的是“这个变量适合立即值吗?”而不是“这是一个常量表达式吗?”

如果我看一下我的x86编译器生成了什么(这个insn根本没有意义),它就在这里:

static char arr[5];

void __attribute__((always_inline)) do_something(char * buf)
{

        // Argument is constant, can use immediate form

        asm volatile ("insn1 %0" : : "r"(buf));

        unsigned long tmp = (unsigned long)buf;

        asm volatile("insn2 %0" : : "r"(tmp));

}


int main(void)
{
   char brr[5];
   do_something(arr);
   do_something(brr);
}
达到

        .file   "inl.c"
        .text
.globl do_something
        .type   do_something, @function
do_something:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
#APP
# 8 "inl.c" 1
        insn1 %eax
# 0 "" 2
# 12 "inl.c" 1
        insn2 %eax
# 0 "" 2
#NO_APP
        popl    %ebp
        ret
        .size   do_something, .-do_something
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    $arr, %eax
        movl    %esp, %ebp
        subl    $16, %esp
#APP
# 8 "inl.c" 1
        insn1 %eax
# 0 "" 2
# 12 "inl.c" 1
        insn2 %eax
# 0 "" 2
#NO_APP
        leal    -5(%ebp), %eax
#APP
# 8 "inl.c" 1
        insn1 %eax
# 0 "" 2
# 12 "inl.c" 1
        insn2 %eax
# 0 "" 2
#NO_APP
        leave
        ret
        .size   main, .-main
        .local  arr
        .comm   arr,5,4
        .ident  "GCC: (SUSE Linux) 4.5.1 20101208 [gcc-4_5-branch revision 167585]"
        .section        .comment.SUSE.OPTs,"MS",@progbits,1
        .string "OSpwg"
        .section        .note.GNU-stack,"",@progbits
因此,我认为立即生效是有意义的,因为
$arr
可能是立即生效的(而
leal-5(%ebp),%eax
不是)。可能就是不支持上述优化

但另一方面,

            movl    $arr, %eax
            insn1 %eax
不是很糟糕吗

            insn1 $arr

所以它仍然是可以接受的,IMHO。

类型不匹配。为什么参数是
char*
,而不是
char(*)[5]
?@KerrekSB请注意,我将arr的地址作为参数发送,而不是arr本身。@gby我想这是重点。传递
arr
就像传递
&arr[0]
=
char*
,因为数组对象在从左值到右值的转换过程中被转换。OTOH
&arr
已经是
char(*)[5]
类型的右值,因为
arr
char[5]
类型的右值;当您将数组用作右值时,它会衰减为指向第一个成员的指针,因此当传递给函数或执行
arr[i]
或将其分配给指针时,但在执行
&arr
时不是这样,因为
&
对左值有效。@Kos我会争辩,但我不明白这与我的问题有什么关系-无论我使用arr还是&arr,结果都是一样的,所以我现在就闭嘴。你是对的,在大多数情况下,2条指令与1条指令相比似乎没有多大意义。我碰巧编写了非常紧凑的嵌入式实时代码,每个周期都很重要。我同意通常情况并非如此。@gby您可以添加一个宏,该宏的
asm
语句带有
“I”
,这应该比内联语句更可行。您可以保留上述内容,作为计算地址或基于堆栈的地址的替代方法。内联函数实际上不会更改任何内容-手动编码或使用宏不会更改behaviour@gby嗯。。。使用
#使用_imm(buf)do{asm volatile(“insn2%0”):“i”(buf));}和(0)
我得到了所需的行为。如果我用静态的
arr
调用它,它工作正常;如果我用堆栈上的by
brr
调用它,它会失败。如果你把asm volatile放在一个没有if语句的内联函数中,它的工作原理是一样的。堆栈上的数组没有固定地址,因此难怪它不能工作。
            insn1 $arr