【问题标题】:Casting to union field yields to conversion warning转换为联合字段产生转换警告
【发布时间】:2018-03-09 13:59:21
【问题描述】:

我正在使用定义以下联合的 Microchip 微控制器:

__extension__ typedef struct tagT1CONBITS {
  union {
    struct {
      uint16_t :1;
      uint16_t TCS:1;
      uint16_t TSYNC:1;
      uint16_t :1;
      uint16_t TCKPS:2;
      uint16_t TGATE:1;
      uint16_t :6;
      uint16_t TSIDL:1;
      uint16_t :1;
      uint16_t TON:1;
    };
    struct {
      uint16_t :4;
      uint16_t TCKPS0:1;
      uint16_t TCKPS1:1;
    };
  };
} T1CONBITS;
extern volatile T1CONBITS T1CONbits __attribute__((__sfr__));

在我的代码中的某处,我将一个变量定义为一个 8 位无符号整数,我想将其分配给上述联合的字段之一。大致如下:

uint8_t tckps;
// The value of tckps is calculated here by some magic formula
tckps = magicformula();
// We asign the value of tckps to the uC register
T1CONbits.TCKPS = tckps;

我在 gcc 中启用了 -Wconversion 选项,这会导致以下警告:

warning: conversion to 'volatile unsigned char:2' from 'uint8_t' may alter its value

我可以理解为什么 gcc 会警告我。我目前在分配 tckps 变量之前对其进行值检查,所以我知道数据丢失不会成为问题,但我不知道如何满足 gcc 转换检查,因此它不会发出警告我在这种特殊情况下。

如何修复警告?

提前致谢!

编辑:添加工具链信息。

Microchip Language Tool Shell Version 1.33 (Build date: Oct  9 2017).
Copyright (c) 2012-2016 Microchip Technology Inc. All rights reserved
*** Executing: "C:\Program Files (x86)\Microchip\xc16\v1.33\bin\bin/elf-gcc.exe"
   "-v"
Using built-in specs.
COLLECT_GCC=C:\Program Files (x86)\Microchip\xc16\v1.33\bin\bin/elf-gcc.exe
Target: pic30-elf
Configured with: /home/xc16/release-builds/build_20171009/src/XC_GCC/gcc/configure --build=i386-linux --host=i386-mingw32 --target=pic30-elf --disable-lto --disable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --disable-hosted-libstdcxx --with-gnu-as --with-gnu-ld --enable-languages=c --disable-nls --disable-libgomp --without-headers --disable-libffi --disable-bootstrap --prefix=/bin --libexecdir=/bin --program-prefix=pic30- --with-libelf=/home/xc16/release-builds/build_20171009/bin/XC_GCC-elf-mingw32-xclm/host-libs/ --with-dwarf2 --with-gmp=/home/xc16/release-builds/build_20171009/bin/XC_GCC-elf-mingw32-xclm/host-libs --with-ppl=/home/xc16/release-builds/build_20171009/bin/XC_GCC-elf-mingw32-xclm/host-libs --with-cloog=/home/xc16/release-builds/build_20171009/bin/XC_GCC-elf-mingw32-xclm/host-libs --with-zlib=/home/xc16/release-builds/build_20171009/bin/XC_GCC-elf-mingw32-xclm/host-libs --with-bugurl=http://www.microchip.com/support --with-host-libstdcxx=-Wl,-Bstatic,-lstdc++,-Bdynamic,-lm
Thread model: single
gcc version 4.5.1 (XC16, Microchip v1.33) Build date: Oct  9 2017 (Microchip Technology)

【问题讨论】:

  • 你离minimal reproducible example不远了。
  • 无法用 gcc 6 重现
  • 我可以用 gcc 4.9.x 重现。
  • 个人意见:我认为-Wconversion不应该一直保持启用状态。它往往会发出一些错误警报,这些错误警报需要丑陋的强制转换或编译指示才能静音。噪声与收益比不是最佳的。
  • 在我的例子中,这个标志导致了非常有用的发现。我个人更喜欢让它保持启用状态,尽管我可能不得不花时间在那里留下一些丑陋的演员表。

标签: c gcc embedded bit-fields microchip


【解决方案1】:

这让我们摆脱了警告:

#include <stdint.h>

typedef struct tagT1CONBITS {
  union {
    struct {
      uint16_t :1;
      uint16_t TCS:1;
      uint16_t TSYNC:1;
      uint16_t :1;
      uint16_t TCKPS:2;
      uint16_t TGATE:1;
      uint16_t :6;
      uint16_t TSIDL:1;
      uint16_t :1;
      uint16_t TON:1;
    };
    struct {
      uint16_t :4;
      uint16_t TCKPS0:1;
      uint16_t TCKPS1:1;
    };
  };
} T1CONBITS;

volatile T1CONBITS T1CONbits;

uint8_t (*magicformula)(void);

int main(void)
{
    uint8_t tckps;
    // The value of tckps is calculated here by some magic formula
    tckps = magicformula() ;
    // We asign the value of tckps to the uC register
    T1CONbits.TCKPS = (uint8_t)(tckps & 3); // This fixes the warning

    return 0;
}

我编译它:

gcc -Wall -Wconversion test2.c

我看到的问题是编译器无法检查未超出变量范围的函数边界。如果您在使用时这样做,编译器可以检查这一点。

强制转换是为了避免在表达式提升为 int 时出现警告。

【讨论】:

  • 虽然 OP 似乎没有使用除赋值以外的任何操作数,因此没有进行任何提升。
  • 是的,但是通过 and'ing 将值提升为 int。所以我不得不再次削减它。 @Lundin
  • @Lundin 你能测试一下这个答案吗?
  • @Jean-FrançoisFabre 显然这是 gcc 的一个已知问题,请参阅我的回答。 Wolfgang 的变通方法似乎是解决它的最佳方法,尽管从 C 标准的角度来看,不需要掩码。
  • 这是我目前首选的解决方案。它解决了我的问题,对我来说添加一个操作是一个合理的权衡。谢谢!
【解决方案2】:

当使用-Wconversion 编译时,这是一个带有 gcc 编译器的known issue 39170。从 gcc 4.3.x 和更高版本开始存在问题。他们可能已经在某个较新的版本中解决了这个问题,但我找不到任何相关信息。

如 Wolfgang 的回答中所示,一个可能的变通办法是将值位掩码为位掩码。

【讨论】:

  • 这可能已经修复。我在 6.2.1 中没有收到警告
  • 我确实在 gcc 4.9.1 中收到了警告,并且可以使用 Wolfgang 建议的修复程序将其静音,这也是链接的 Bugzilla 中建议的相同修复程序。
  • 感谢您指出这一点。我同意这可能已在最近的版本中得到修复,但目前我必须处理这个问题。在 Microchip 发布更新的 GCC 版本之前,Wolfgang 是迄今为止对我来说最好的解决方案。
  • @AntonioVázquezBlanco 您使用的是哪个工具链,Atmel Studio? (或者在 Microchip 合并后叫什么)
  • @Lundin 工具链称为 XC16。它不是用于 Atmel uC,而是用于 Microchip uC。 IDE 是 MPLAB X。对它不是很满意,但据我所知,它比几年前可用的解决方案要好得多。我已将工具链信息添加到原始消息中。
【解决方案3】:

您可以使用#pragma GCC diagnostic 选择性地忽略 gcc 警告。下面是一个如何使用它的示例:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
    T1CONbits.TCKPS = tckps;
#pragma GCC diagnostic pop

push pragma 存储诊断警告的当前状态。 ignored pragma 然后告诉编译器从那时起忽略指定的警告。 pop pragma 然后恢复之前的诊断状态,因此将打印任何其他可能出现转换警告的地方。

最终结果是仅针对编译指示之间的特定源代码行禁止显示警告。

【讨论】:

  • 但这并不能解释为什么首先出现警告。
  • @Lundin:问题表明 OP 理解为什么会出现警告:右侧能够表示比左侧更多的值,因此分配可能会丢失值。你想要更多的解释吗?这将是一个与 OP 所要求的不同的问题。
  • @EricPostpischil 鉴于这显然是 gcc 中的一个已知错误,那么是的,最好提及警告的原因。
  • @Lundin:什么是错误?分配可能会溢出目的地。编译器发出警告。为什么错了?
  • @EricPostpischil 这是一个错误,因为编译器没有提供合理的解决方法。请参阅链接的 Bugzilla 讨论。
猜你喜欢
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2011-07-05
  • 2014-02-16
相关资源
最近更新 更多