相似的类型(`int16_t`和`short`)在引用实例化期间产生不同的行为

问题描述 投票:0回答:1

根据我为变量选择的类型,我遇到了以下错误。

/home/zak/Development/Arduino/generated_examples/ArduinoIoTCloud_Basic/thingProperties.h: In function 'void initProperties()':
/home/zak/Development/Arduino/libraries/ArduinoIoTCloud/src/ArduinoIoTCloud.h:116:64: error: cannot bind non-const lvalue reference of type 'int16_t& {aka int&}' to an rvalue of type 'int16_t {aka int}'
 #define addProperty( v, ...) addPropertyReal(v, #v, __VA_ARGS__)
                                                                ^
/home/zak/Development/Arduino/generated_examples/ArduinoIoTCloud_Basic/thingProperties.h:32:16: note: in expansion of macro 'addProperty'
   ArduinoCloud.addProperty(potentiometer, 2, Permission::Read).publishOnChange(10);
                ^
In file included from /home/zak/Development/Arduino/generated_examples/ArduinoIoTCloud_Basic/ArduinoIoTCloud_Basic.ino:17:0:
/home/zak/Development/Arduino/libraries/ArduinoIoTCloud/src/ArduinoIoTCloud.h:158:15: note:   initializing argument 1 of 'Property& ArduinoIoTCloudClass::addPropertyReal(int16_t&, String, int, Permission)'
     Property& addPropertyReal(int16_t& property, String name, int tag, Permission const permission);
               ^~~~~~~~~~~~~~~

这是

addPropertyReal()
的正文:

Property& ArduinoIoTCloudClass::addPropertyReal(int16_t& property, String name, int tag, Permission const permission)
{
  Property* p = new CloudWrapperInt16(property);
  return addPropertyReal(*p, name, tag, permission);
}

问题发生在

new
ing
CloudWrapperInt16
时:

class CloudWrapperInt16 : public CloudWrapperBase {
  private:
    int16_t  &_primitive_value,
             _cloud_value,
             _local_value;
  public:
    CloudWrapperInt16(int16_t& v) : _primitive_value(v), _cloud_value(v), _local_value(v) {}
...

^^ 如您所见,

_primitive_value
是参考。

16位架构,avr-gcc编译器

奇怪的是,当我通过实际的

int
int16_t
时,这会起作用。但是,每当我传入一个等效但必须转换为
int16_t
的值(例如
short
)时,我都会遇到此错误。

成功(

int16_t
):(编译时没有警告)

int16_t potentiometer;
...
void initProperties() {
...
  ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);

成功(

int
):(编译时没有警告)

int potentiometer;
...
void initProperties() {
...
  ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);

失败 (

short
): (错误如上所示)

short potentiometer;
...
void initProperties() {
...
  ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);

编辑: 最初,我忘记提及这个特定示例是针对 16 位平台进行编译的。所以

int
short
int16_t
的大小应该相同。

32位架构,arm-none-eabi-gcc编译器

在一个非常奇怪的转折中,当我通过

short
int16_t
时,这会起作用。但是,每当我传入
int
值时,我都会遇到类似的错误。

成功(

int16_t
):(编译时没有警告)

int16_t potentiometer;
...
void initProperties() {
...
  ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);

成功(

short
):(编译时没有警告)

short potentiometer;
...
void initProperties() {
...
  ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);

FAIL (

int
): (类似错误如上所示)

int potentiometer;
...
void initProperties() {
...
  ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);

有人可以解释一下类型转换到底发生了什么吗?

我正在寻找一种符合 POSIX 标准的方法,以便编译器同等对待它们,或者一种增强代码以允许其工作的方法。任何解决方案都需要针对多种架构(16 位、32 位等)进行编译,并且需要在多个工具链上工作(

avr-gcc
arm-none-eabi-g++
等)。

注意:我无法控制代码库;这是一个大型开源项目。我真的需要一个外科手术解决方案,因为重构工作越广泛,PR 被接受就越难。

c++ types casting reference embedded
1个回答
0
投票

注意:这个答案欢迎改进,仅作为其他人的面包屑。它基于经验观察,而不是深入研究相关编译器的源代码或研究 ISO。

看起来

avr-gcc
编译器别名
int16_t
int
(反之亦然),并且
short
是单独定义的。而
arm-none-eabi-gcc
编译器别名
int16_t
short
(反之亦然)。

成功可以归因于它们实际上是相同的数据类型,因此不需要强制转换或转换。因此,失败源于编译器认为有必要进行转换或强制转换的事实。

一旦发生强制转换,就会创建一个临时对象。显然,临时对象不能绑定到非常量引用(这使得错误消息有意义),因为该引用没有与其关联的存储,因此无法在运行时修改。

如果您很难概念化这一点,请考虑从整数到浮点数的转换。不可能通过修改浮点值来更新基础整数。

就我而言,我需要的解决方案是进一步模板化基于整数的类和函数。这最终抽象了单个通用实现背后的所有整数运算。

© www.soinside.com 2019 - 2024. All rights reserved.