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)
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With