Search code examples
cgccembeddedbit-fieldsmicrochip

Casting to union field yields to conversion warning


I am using a Microchip microcontroller which defines the following union:

__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__));

Somewhere in my code I am defining a variable as a 8 bit unsigned integer which I would like to assign to one of the fields of the union above. Somewhat as follows:

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;

I have the -Wconversion option enabled in gcc which leads to the following warning:

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

I can understand why gcc is warning me. I am currently preforming a value check on the tckps variable before assigning it so I know that the data loss is not going to be a problem, but I don't know how to satisfy gcc conversion check so that it doesn't warn me in this particular case.

How can I fix the warning?

Thanks in advance!

EDIT: Added toolchain information.

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)

Solution

  • This lets met get rid of the warning:

    #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;
    }
    

    I compile it with:

    gcc -Wall -Wconversion test2.c
    

    The problem I see is that the compiler can't check over the function boundaries that the range of the variable is not exceeded. If you do it at the point of use the compiler can check this.

    The cast is to avoid a warning when the expression is promoted to int.