EDIT: problem explained more in depth here (thank you @Eric Postpischil). It seems to be a bug in GCC.
First, let me start with some context: the code I'm writing is using an API I can't change, on a GCC version I can't change, with compilation flags I'm not allowed to remove, and when I'm done with it must have precisely zero warnings or #pragmas.
EDIT: no unions either.
EDIT2: assume the build system also uses -Wall -ansi -pedantic and every other warnings under the sun. I'll confirm the GCC version tomorrow but I'm fairly certain it's not above GCC 7. In the meantime I'm testing with GCC 6.3.
EDIT3: I'm marking the issue as 'answered'. For completeness' sake, I'm adding some more information below:
I've checked the compiler version being used, and it's not pretty. We're using Mingw and a gcc.exe --version
tells me it's GCC 3.4.5.
Furthermore, compilation flags include wall wextra wcast-qual wpointer-arith wconversion wsign-conversion
along with others that are not relevant to the problem at hand.
The problem
Consider the following code:
#include "stdio.h"
#include "stdint.h"
typedef uint32_t MyType[4];
const MyType* foo(const uint8_t* a)
{
return (const MyType*) a;
}
void myapi_foo(const MyType* d) {}
int main()
{
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
myapi_foo(b);
return 0;
}
Compiled with GCC and the -Wcast-qual flag, this code will throw the following warning:
warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual] return (const MyType*) a;
EDIT: to clarify, the error is on this line:
return (const MyType*) a;
The cause of the problem
I know the root cause of the problem is the typedef type MyType
which is in fact an array. Sadly, I do not have the luxury of modifying this typedef, nor the API function myapi_foo
and its dubious choice of parameter type.
To be honest, I don't really understand why is the compiler so unhappy about this cast, so clarifications are more than welcome.
The question
What would be the cleanest way of indicating to the compiler everything should be treated as a pointer to const data?
Discarded and potential solutions
Here are a few 'solutions' that I have found but left me unsatisfied:
- Remove the -Wcast-qual flag. I cannot do that due to code quality rules.
- Add a #pragma to turn off the warning around that part of the code (as shown here). Similarly I'm not allowed to do that.
- Cast the pointer to an integer, then cast back to a pointer (as shown here)
return (const MyType*) (uint32_t) a;
. It's very crude, but usinguint32_t
as memory addresses has precedent in this project so I might have to use it as a last ditch effort. - EDIT: @bruno suggested using an union to side-step the problem. This is a portable and fairly elegant solution. However, the aforementioned code quality rules downright bans the use of unions.
- EDIT: @Eric Postpischil and @M.M suggested using a (const void*) cast
return (const void*) a;
, which would work regardless of the value ofsizeof(MyType*)
. Sadly it doesn't work on the target.
Thank you for your time.