为什么使用函数参数'foo'这样:*(& foo)? [英] Why use a function parameter 'foo' in this way: *(&foo)?

查看:210
本文介绍了为什么使用函数参数'foo'这样:*(& foo)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Linux内核中的代码片段使用了一个这样的函数参数:

  int do_signal(int signr,int eax / *其他参数... * /){
/ * ... * /

*(& eax)= - EINTR;

/ * ... * /
}



代码的目的是将-EINTR放在eax存在的内存中,但是我不能告诉为什么只是分配给eax将不会工作:

  eax = -EINTR 

编译器如何在

一个可能的目的是保持寄存器中的 eax 变量。如果我们查看 C99草案标准,请参阅 6.5.3.2 地址和间接运算符


一元&运算符产生其操作数的地址。 [...]如果操作数是一元运算符的结果,那么
运算符和&运算符,并且结果是,如同两个
省略
,除了运算符的约束仍适用
,结果不是lvalue。[...]


在脚注强调我的进展):


因此,& * E等同于E是空指针)和
&(E1 [E2])到((E1)+(E2))。 总是如此,如果E是函数
指示符或者是一元运算符的有效操作数的左值,
运算符,*& E是等于E
的函数指示符或左值。


&运算符


运算符应该是一个函数
指示符,一个[]或一元*运算符的结果,或者一个左值
指定一个不是位字段并且未声明为
寄存器存储类别说明符


这是有意义的,因为我们不能取寄存器的地址并且因此通过执行操作的地址,它们可能已经试图防止编译器完全在寄存器中执行操作并且确保修改特定存储器位置中的数据。



由于ouah指出,这并不妨碍编译器优化有效的无操作,而是 Linux内核中的GCC入侵。 Linux依赖于许多 gcc 扩展,并且考虑到 0.12 是一个非常旧的内核 gcc 可能已经保证行为或可能有意外可靠工作的方式,但我找不到任何文档说。


A code snippet in Linux kernel 0.12 use a function parameter like this:

int do_signal(int signr, int eax /* other parameters... */) {
    /* ... */

    *(&eax) = -EINTR;

    /* ... */
}

The purpose of the code is to put -EINTR to the memory where eax lives, but I can not tell why it won't work if just assigning to eax:

eax = -EINTR

How would the compiler make a difference between eax and *(&eax)?

解决方案

One possible intention could be to keep the eax variable out of a register. If we look at the C99 draft standard we see that section 6.5.3.2 Address and indirection operators says (emphasis mine):

The unary & operator yields the address of its operand. [...]If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.[...]

in footnote 87 it says (emphasis mine going forward):

Thus, &*E is equivalent to E (even if E is a null pointer), and &(E1[E2]) to ((E1)+(E2)). It is always true that if E is a function designator or an lvalue that is a valid operand of the unary & operator, *&E is a function designator or an lvalue equal to E.

we find the following constraint on & operator:

The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

Which makes sense since we can not take the address of a register and so by performing an address of operation they may have been trying to prevent the compiler from performing the operations completely in registers and ensure that data in specific memory locations are modified.

As ouah points out this does not prevent the compiler from optimizing what is effectively a no-op away but as documented in GCC hacks in the Linux kernel. Linux has relied on many gcc extensions and considering that 0.12 is a very old kernel gcc may have guaranteed that behavior or may have by accident reliably worked that way but I can not find any documentation that says so.

这篇关于为什么使用函数参数'foo'这样:*(& foo)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆