【问题标题】:Is a c++ dereference an lvalue or an rvalue?c++ 取消引用是左值还是右值?
【发布时间】:2017-12-10 18:52:35
【问题描述】:

我相信我理解rvaluelvalue 的含义。我不清楚的是取消引用是否是rvalue

考虑一下:

#define GPIO_BASE             0x20200000
#define GPFSEL1               (*(volatile unsigned int *)(AUX_MU_BASE + 0x4))

GPFSEL1 是对 unsigned int 指针的取消引用。该无符号整数指针是硬件寄存器的物理地址。

我读到这是裸机编程中直接访问硬件寄存器的常用技术。到目前为止,我可以毫无问题地使用它。

现在我想要一个 referenceGPFSEL1 作为结构的成员。这可能吗?

struct MotorControl
{
    u8 pwm_pin;
    u8 ctrla_pin;
    u8 ctrlb_pin;
    volatile unsigned int* MYGPFSEL; // this is not the same thing so does not work
}

鉴于下面的这个函数,引用在别处定义的GPFSEL1 的正确方法是什么以及如何取消引用它来设置它的值?

MotorContorl group
group.MYGPFSEL = ?
void set(unsigned char pin_number, bool high)
{
if (high)
    {
      // how to correct this statement
      group.MYGPFSEL |= 1<< pin_number;
    } 
}

【问题讨论】:

  • C 没有定义右值,AFAIR。
  • 移除标签
  • 这个有点不清楚。该结构与左值和右值有什么关系?
  • 这基本上就是引用。您可以使用volatile unsigned int &amp;MYGPFSEL;
  • @SamHammamy 请注意,在 C++ 中,“引用”是一个非常具体的东西,因此请确保这是您真正想要的(您可能不想要,当前使用指针的代码是做你正在做的)

标签: c++ dereference bare-metal


【解决方案1】:

“取消引用”是一个动词 - 您取消引用一个指针以访问它指向的值。

类型转换很简单——如果你有一个指向整数的指针,并且你取消了它的引用,那么你现在正在使用一个整数。它是一个左值,因为它(通过构造)占用内存中的一个位置,并且您可以(通常)修改一个位置。

int x = 10;
int* xptr = &x;
*xptr = 5; // *xptr is an lvalue
std::cout << "X: " << x << std::endl; // Prints 5

但是,指针需要指向内存中的某个位置。如果你刚开始

int* xptr;
*xptr = 5;

你会得到一个错误,因为你试图取消引用一个不指向有效内存地址的指针。 (如果是这样,那纯属巧合,您会错误地更改值。)

如果您希望将 GPFSEL1 的引用作为 MotorControl 结构的成员,您将无法初始化该结构,除非将其传递给它要引用的对象。相反,您可能想要的是结构内的指针,这更容易使用:

MotorControl myMotorControl;
myMotorControl.MYGPFSEL = GPFSELF1;

【讨论】:

  • 重点是GPFSEL 是在其他地方定义的。我想在结构中复制它。我不能只做:volatile unsigned int * MYGPFSEL = something
  • 我已经更新了我的答案。在结构中进行引用可能不是您想要的,因为您需要使用引用将引用的值来初始化结构。您的结构当前是一个指针,您可以将其初始化为指向 GPFSEL1
  • 我想我明白了。然后,当我在需要时通过取消引用操作 MYGPFSEL 指向的任何内容时。
  • 最后一句应该是:“您的结构当前使用指向 MYGPFSEL 的指针。”是的,您可以通过取消引用 MYGPFSEL 并为其分配新值来更新 MYGPFSEL 指向的任何内容。
  • 感谢@GraphicsMuncher。这就是为我结束编译的内容。 struct X {volatile unsigned int* GPFSEL}this-&gt;x.MYGPFSEL = &amp;GPFSEL1*(this-&gt;x.GPFSET) |= 1&lt;&lt; pin_number; 仍然不确定它是否是正确的代码。裸机测试需要时间:)
【解决方案2】:

您当前的方法可以正常工作,您只需要适当地初始化成员变量,例如

struct MotorControl control;
control.MYGPFSEL = (volatile unsigned int *)(AUX_MU_BASE + 0x4);

或者,您可以将其初始化为

control = &GPFSEL1; 

假设您已在原始问题中定义 GPFSEL1:

#define GPFSEL1 (*(volatile unsigned int *)(AUX_MU_BASE + 0x4))`

现在你可以读取寄存器了:

 foo = *control.MyGPFSEL;

或设置寄存器:

 *control.MyGPFSEL = 123;

【讨论】:

  • 是的,没错,但GPFSEL 是在其他地方定义的,我希望能重用它
  • 你能解释一下你的意思吗?你在哪里定义 GPFSEL ?你是怎么定义的?如果你不希望它成为你的结构的成员,你为什么把它放在那里?
  • 我有一个 gpio.h 文件,其中保存了所有 GPIO 物理地址。在里面我有。 #define GPIO_BASE 0x20200000#define GPFSEL1 (*(volatile u32 *)(GPIO_BASE + 0x4))、GPFSEL2、GPFSEL3、...
  • 然后用control.MYGPFSEL = &amp;GPFSEL1 ;初始化成员
  • 这个答案最接近解决方案。如果可以,请将其更新为:struct X {volatile unsigned int* GPFSEL}x.MYGPFSEL = &amp;GPFSEL1*(x.GPFSET) |= 1&lt;&lt; pin_number; 或更干净,那么我可以接受它作为正确答案。
【解决方案3】:

这是一个很容易回答的问题,取消引用可以是赋值的左侧,所以它是一个左值。

简单的案例说明:

char sz[] {"hello"};
*sz = 'j';

如果某物可以作为赋值的左侧,则根据定义它是左值。

【讨论】:

  • 这是非常有缺陷的推理。它可以很容易地成为对对象的引用。这是一个左值,因为标准是这样说的
  • 如果某物可以作为赋值的左侧,则根据定义它是左值。 ...考虑struct foo {}; foo{} = {};。我在左边有一个prvalue,但我可以分配给它。
  • 是的,这不是左值的定义(考虑到 c++11 用它的创新造成的所有混乱),它更像是一个经验法则,它主要适用于 @987654324 @ 或 c++98.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多