Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 wich 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 perfoming a value check on the tckps variable before asigning 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)
like image 956
Antonio Vázquez Blanco Avatar asked Mar 09 '18 13:03

Antonio Vázquez Blanco


3 Answers

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.

like image 200
Wolfgang Avatar answered Oct 10 '22 02:10

Wolfgang


This is a known issue 39170 with the gcc compiler specifically, when compiling with -Wconversion. The problem exists from gcc 4.3.x and later versions. It is possible that they have fixed the issue in some newer version, but I couldn't find any information regarding it.

A possible dirty work-around is to mask the value bit a bit mask as shown in the answer by Wolfgang.

like image 33
Lundin Avatar answered Oct 10 '22 02:10

Lundin


You can selectively ignore gcc warnings with #pragma GCC diagnostic. Below is an example of how you can use this:

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

The push pragma stores the current state of diagnostic warnings. The ignored pragma then tells the compiler to ignore the specified warning from that point on. The pop pragma then restores the prior diagnostic state, so any other places where a conversion warning might occur will be printed.

The end result is that the warning is suppressed for only the specific source lines between the pragmas.

like image 1
dbush Avatar answered Oct 10 '22 03:10

dbush