Why can't I initialize ("initializer element is not constant") a struct with a truncated function pointer?
-
I need to save space and reduce some of my function pointers from 32-bit to 16-bit and this is ok since the flash region I've specified in the linker script is only 32 kBytes. Does anybody know how I can make my 3rd example below compile properly?
typedef struct {
uint16_t myFunctPtrTruncated;
} myUint16struct_s;typedef struct {
void* myFunctPtr;
} myVoidstruct_s;static void myDummyFunc() {}
myVoidstruct_s myStruct1 = { myDummyFunc }; // Ok
myUint16struct_s myStruct2 = { 0 }; // Ok
myUint16struct_s myStruct3 = { (uint16_t)(uint32_t)myDummyFunc }; // Error: "initializer element is not constant" -
I need to save space and reduce some of my function pointers from 32-bit to 16-bit and this is ok since the flash region I've specified in the linker script is only 32 kBytes. Does anybody know how I can make my 3rd example below compile properly?
typedef struct {
uint16_t myFunctPtrTruncated;
} myUint16struct_s;typedef struct {
void* myFunctPtr;
} myVoidstruct_s;static void myDummyFunc() {}
myVoidstruct_s myStruct1 = { myDummyFunc }; // Ok
myUint16struct_s myStruct2 = { 0 }; // Ok
myUint16struct_s myStruct3 = { (uint16_t)(uint32_t)myDummyFunc }; // Error: "initializer element is not constant" -
I need to save space and reduce some of my function pointers from 32-bit to 16-bit and this is ok since the flash region I've specified in the linker script is only 32 kBytes. Does anybody know how I can make my 3rd example below compile properly?
typedef struct {
uint16_t myFunctPtrTruncated;
} myUint16struct_s;typedef struct {
void* myFunctPtr;
} myVoidstruct_s;static void myDummyFunc() {}
myVoidstruct_s myStruct1 = { myDummyFunc }; // Ok
myUint16struct_s myStruct2 = { 0 }; // Ok
myUint16struct_s myStruct3 = { (uint16_t)(uint32_t)myDummyFunc }; // Error: "initializer element is not constant" -
I am using System Workbench (=gcc?) and I get error (not warning) message "initializer element is not constant".
-
I need to save space and reduce some of my function pointers from 32-bit to 16-bit and this is ok since the flash region I've specified in the linker script is only 32 kBytes. Does anybody know how I can make my 3rd example below compile properly?
typedef struct {
uint16_t myFunctPtrTruncated;
} myUint16struct_s;typedef struct {
void* myFunctPtr;
} myVoidstruct_s;static void myDummyFunc() {}
myVoidstruct_s myStruct1 = { myDummyFunc }; // Ok
myUint16struct_s myStruct2 = { 0 }; // Ok
myUint16struct_s myStruct3 = { (uint16_t)(uint32_t)myDummyFunc }; // Error: "initializer element is not constant"Your statement 3 as written will only compile in C++ it isn't valid C code. Which is why the person who tried it on VC++ it worked. In C "myDummyFunc" can not be typecast to an address like in C++, in C "&myDummyFunc" is the pointer address that needs typecasting Remember what that pesky "&" character means in C The first case you list was defined as valid in C99, but your 3rd case is junk and correctly rejected So try proper C code using the "&" so it understands what you are trying to do
myUint16struct\_s myStruct3 = { (uint16\_t)(uint32\_t)&myDummyFunc };
Now if you want to do it properly so its portable the correct way is to use uintptr_t for the translation and C99 dot format This allows you move the pointer anywhere within the struct and it sets correctly
myUint16struct_s myStruct4 = { .myFunctPtrTruncated = (uint16_t)(uintptr_t)&myDummyFunc };
In C99, uintptr_t will put some safety around your code because it is defined as
an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer
In vino veritas
-
Your statement 3 as written will only compile in C++ it isn't valid C code. Which is why the person who tried it on VC++ it worked. In C "myDummyFunc" can not be typecast to an address like in C++, in C "&myDummyFunc" is the pointer address that needs typecasting Remember what that pesky "&" character means in C The first case you list was defined as valid in C99, but your 3rd case is junk and correctly rejected So try proper C code using the "&" so it understands what you are trying to do
myUint16struct\_s myStruct3 = { (uint16\_t)(uint32\_t)&myDummyFunc };
Now if you want to do it properly so its portable the correct way is to use uintptr_t for the translation and C99 dot format This allows you move the pointer anywhere within the struct and it sets correctly
myUint16struct_s myStruct4 = { .myFunctPtrTruncated = (uint16_t)(uintptr_t)&myDummyFunc };
In C99, uintptr_t will put some safety around your code because it is defined as
an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer
In vino veritas
-
Set the compiler flags -std=c11 or -std=c99 either standard will accept the code The portable case has to work or you are on an old C89 compiler which I find odd given it accepts the shortcut syntax in 1 The only other choice is you are on something like a PIC where you have to use builtins to get function addresses because of the crazy 32K block arrangements on memory
In vino veritas