How to eliminate the "discard qualifier" warning?

15,207

Solution 1

No, you can't turn that warning off. It's telling you you're violating the type system. If you want to call func you either need to pass it pointers to non-volatile data or change the function signature to accept pointers to volatile data.

Solution 2

The Standard allows compilers to do anything they like if a non-qualified pointer is used to access a volatile-qualified object. This allows for platforms where some volatile-qualified objects may require special instructions to access them, where e.g. a write via volatile uint16_t* might do generate code equivalent to:

if ((uintptr_t)ptr >= 0xFFFF0000)
  __outport16(0xFFFF & (uintptr_t)ptr, value);
else
  (uint16_t*)ptr = value;

If a compiler writer takes the attitude that compilers should only exploit such freedoms on obscure platforms were doing otherwise would be expensive, and should provide sensible behaviors on platforms where doing so would cost almost nothing, and if the calling code in the original example knows that no outside entities will access Y during the execution of func, then code targeting that compiler will be able to achieve the required behavior without a diagnostic merely by casting Y's address to a float*. Unfortunately, the people maintaining gcc and clang seem to believe that when the Standard refers to "non-portable or erroneous constructs", it really means "non-portable, i.e. erroneous, constructs" rather than "constructs which are not portable to every single conforming machine in the Universe, and would be erroneous if such portability were intended. Casting the pointer to float* will silence the warning on gcc or clang, but I wouldn't count on it causing them to yield sensible code.

Share:
15,207
ysap
Author by

ysap

I've been a computers/computing enthusiast since many years ago. Started coding FORTRAN on punched cards, then moved to BASIC on my MC6809 based DRAGON-64 and then the x86 IBM-PC era. I had the opportunity of working on mainframes, minis, workstations, PC's and embedded hardware. Today I am doing mainly embedded coding - C and ASM on various processors, and on various programming environments and toolchains like MS Visual Studio, Eclipse CDT, ARM DS and more. Was lucky enough to be at the right time at the right place to get to work as a VLSI designer for a top tier chip company, working on a world class processor family. Always looking to solving problem in the most elegant way! - Yaniv Sapir

Updated on June 04, 2022

Comments

  • ysap
    ysap about 2 years

    Using GCC and C99 mode, I have a function declared as:

    void func(float *X);
    

    When I call the function, I use a volatile array Y:

    volatile float Y[2];
    int main()
    {
        func(Y);
        return 0;
    }
    

    When compiling (with -Wall), I get the following warning:

    warning: passing argument 1 of ‘func’ discards qualifiers from pointer target type
    blah.c:4: note: expected ‘float *’ but argument is of type ‘volatile float *’
    

    I can eliminate it with an explicit (float *) type cast, but this repeats in many places in the code.

    Is there a way to eliminate this specific warning, with an option or a pragma (or something equivalent)?

  • ysap
    ysap almost 12 years
    Thanks. This is actually interesting (and arguable, in a way). I don't really change the type of the variable. The volatile qualifier is a signal for the optimizer. So I wonder why it is regarded as a violation of the type system?!
  • Jonathan Wakely
    Jonathan Wakely almost 12 years
    In the same way as passing a const int* to a function func(int*) is a violation of the type system.
  • rubenvb
    rubenvb almost 12 years
    @ysap volatile, just like const, is part of the type.
  • ysap
    ysap almost 12 years
    @rubenvb, Jonathan - While accepting your comments, I do see a difference between the const and the volatile qualifiers. The way I understand it, const qualifier gives compile time (as opposed to optimize time) information about the object. For example, it should prevent me from assigning a value to that object, and I should get a diagnostics if I try to do that. With volatiles, there is no such problem (that I can imagine right now).
  • ysap
    ysap almost 12 years
    ... but, when you come to think about it, the point may be that the compiler guards from case where a volatile object is passed to a non-volatile function, and that function, having non-volatile arguments, is being over-optimized to teh point where the result, per the volatile object, is incorrect!
  • ysap
    ysap almost 12 years
    So I guess this explanation completes the answer.
  • HonkyTonk
    HonkyTonk almost 12 years
    @ysap Could you please explain why a const marker is not used in the optimization stage? Specifying that a variable will remain constant is very valuable information during optimization.
  • ysap
    ysap almost 12 years
    @HonkyTonk - Maybe I was unclear - it may certainly be useful for optimization, but it is definitely important for compilation, like I mentioned. I cannot see why volatile would be important at compile time, though. (In this limited context, I take "compilation" as the translation from C to some low- or intermediate-level representation)
  • Jonathan Wakely
    Jonathan Wakely almost 12 years
    @HonkyTonk, not as valuable as you might think. On a declaration const allows the compiler to put the variable in read-only memory, but on a pointer or reference const does not mean the variable can't change, only that it can't be changed through that pointer/reference. And if the compiler knows there are no writes to a variable it can optimize its use even if it isn't const. See gotw.ca/gotw/081.htm for more
  • Michael Conlen
    Michael Conlen about 10 years
    Suppose your function is already compiled into a .o or a lib just waiting to be linked to. It may be optimized in ways that suppose non-volatile behavior while the calling code expects the function to treat the variable as volatile.