强制转换为联合字段会产生转换警告

Casting to union field yields to conversion warning

我正在使用定义以下联合的 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)

这样可以消除警告:

#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 时出现警告。

您可以使用 #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 然后恢复先前的诊断状态,因此将打印可能发生转换警告的任何其他地方。

最终结果是仅针对 pragma 之间的特定源代码行抑制了警告。

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

一个可能的脏 work-around 是将值位掩码为位掩码,如 Wolfgang 的答案所示。