5

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)
Jason Aller
  • 3,541
  • 28
  • 38
  • 38

3 Answers3

2

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.

Wolfgang
  • 48
  • 4
  • 1
    The OP doesn't seem to use any operands other than assignment though, so no promotion takes place. – Lundin Mar 09 '18 at 14:23
  • Yes, but by and'ing the value gets promoted to int. So I have to cut it down again. @Lundin – Wolfgang Mar 09 '18 at 14:28
  • @Lundin could you test this answer? – Jean-François Fabre Mar 09 '18 at 14:33
  • @Jean-FrançoisFabre Apparently this is a known problem with gcc, see my answer. Wolfgang's work-around seems to be best way to solve it, although from a C standard perspective, the masking shouldn't be needed. – Lundin Mar 09 '18 at 14:40
  • This is my preferred solution right now. It fixes my issue and for me adding one operation is a reasonable tradeoff. Thank you! – Antonio Vázquez Blanco Mar 12 '18 at 10:14
  • @AntonioVázquezBlanco Likely, the mask does not result in any different machine code. So there shouldn't be any trade-off at all. However, this is a weird work-around by gcc, given how the C language works, with implicit type promotions. – Lundin Mar 13 '18 at 12:51
  • @Lundin I have not checked the resulting dissasembly but from what I've seen in this particular compiler I would say that it is quite probable that it will perform the operation. Anyways we are talking about a simple instruction. It cannot be considered even a tradeoff in terms of execution but maybe in terms of ugly casting in the middle of code that should execute without problems. – Antonio Vázquez Blanco Mar 13 '18 at 15:39
2

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • this has probably been fixed. I don't get the warning in 6.2.1 – Jean-François Fabre Mar 09 '18 at 14:41
  • I do get the warning in gcc 4.9.1 and can silence it with the fix suggested by Wolfgang, which is also the very same fix suggested in the linked Bugzilla. – Lundin Mar 09 '18 at 14:42
  • Thanks for pointing this out. I would agree that this has probably been fixed in recent versions but for the time being I have to deal with this. Wolfgang is the best solution for me so far until Microchip releases a newer GCC version. – Antonio Vázquez Blanco Mar 12 '18 at 10:29
  • @AntonioVázquezBlanco Which tool chain are you using, Atmel Studio? (Or whatever that one is called after Microchip merger) – Lundin Mar 12 '18 at 11:54
  • @Lundin the toolchain is called XC16. It is not for an Atmel uC, it is for a Microchip uC. The IDE is MPLAB X. Not very happy with it but from what I have been told it is much better than the solutions available a couple of years ago. I've added the toolchain info to the original message for you. – Antonio Vázquez Blanco Mar 12 '18 at 17:11
  • @AntonioVázquezBlanco Isn't that MPLAB compiler then, rather than gcc? Or did Microchip finally quit the compiler business? – Lundin Mar 13 '18 at 07:24
  • @Lundin XC16 is a port of the GCC compiler. They have free versions and licensed ones. They did not quit the compiler business. – Antonio Vázquez Blanco Mar 13 '18 at 11:30
1

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 3
    But this doesn't explain _why_ the warning appears in the first place. – Lundin Mar 09 '18 at 14:20
  • 1
    @Lundin: The question states the OP understands why the warning occurs: The right side is capable of representing more values than the left side, so the assignment could lose the value. Did you want more explanation than that? It would be a different question from what OP is asking. – Eric Postpischil Mar 09 '18 at 14:39
  • @EricPostpischil Given that this is apparently a known bug in gcc, then yes, it would be nice to mention the reason for the warning. – Lundin Mar 09 '18 at 14:41
  • @Lundin: What is the bug? The assignment could overflow the destination. The compiler warns. Why is that wrong? – Eric Postpischil Mar 09 '18 at 18:41
  • @EricPostpischil It's a bug since the compiler provides no sensible work-around. See the linked Bugzilla discussion. – Lundin Mar 12 '18 at 07:42
  • I prefer not to use this fix as it just silences the warning. I would prefer to understand what is happening behind the scenes and how the checks are performed. I may use it as a last resort in case I cannot perform a check that fixes the issue. – Antonio Vázquez Blanco Mar 12 '18 at 10:09