I've inherited some old code that assumes that an int
can store values from -231 to 2^31-1, that overflow just wraps around, and that the sign bit is the high-order bit. In other words, that code should have used uint32_t
, except that it wasn't. I would like to fix this code to use uint32_t
.
The difficulty is that the code is distributed as source code and I'm not allowed to change the external interface. I have a function that works on an array of int
. What it does internally is its own business, but int
is exposed in the interface. In a nutshell, the interface is:
struct data {
int a[10];
};
void frobnicate(struct data *param);
I'd like to change int a[10]
to uint32_t a[10]
, but I'm not allowed to modify the definition of struct data
.
I can make the code work on uint32_t
or unsigned
internally:
struct internal_data {
unsigned a[10];
};
void frobnicate(struct data *param) {
struct internal_data *internal = (struct internal_data *)param;
// ... work with internal ...
}
However this is not actually correct C since it's casting between pointers to different types.
Is there a way I can add compile-time guards so that, for the rare people for whom int
isn't “old-school” 32-bit, the code doesn't build? If int
is less than 32 bits, the code has never worked anyway. For the vast majority of users, the code should build, and in a way that tells the compiler not to do “weird” things with overflowing int
calculations.
I distribute the source code and people may use it with whatever compiler they choose, so compiler-specific tricks are not relevant.
I'm at least going to add
#if INT_MIN + 1 != -0x7fffffff
#error "This code only works with 32-bit two's complement int"
#endif
With this guard, what can go wrong with the cast above? Is there a reliable way of manipulating the int
array as if its elements were unsigned
, without copying the array?
In summary:
- I can't change the function prototype. It references an array of
int
. - The code should manipulate the array (not a copy of the array) as an array of
unsigned
. - The code should build on platforms where it worked before (at least with sufficiently friendly compilers) and should not build on platforms where it can't work.
- I have no control over which compiler is used and with which settings.