Using Keil MCBSTM32 (STM32F103RB processor) and uVision3 V3.55a
The goal is to "encapsulate" data in C. To do this I want to create access methods (get/put) that are accessible externally, but the data, being declared static, is not.
I also want to appease those who want faster code so I was attempting to "inline" the methods.
The test code is as follows:
#include counter.h static unsigned int counter; /** Method to get counter. */ __forceinline unsigned int get_counter() { return counter; } /** Method to set counter. */ __forceinline void put_counter( unsigned int val) { counter = val; }
The counter.h contains the following:
__forceinline unsigned int get_counter(void); __forceinline void put_counter( unsigned int val);
(Note: tried the declarations in the .h file with and without the __forceinline)
The main() contains:
static unsigned int opt_test; /*---------------------------------------------------------------------------- MAIN function *----------------------------------------------------------------------------*/ int main (void) { stm32_Init (); // STM32 setup GPIOB->ODR |= (1 << (ledPos+8)); // switch on initial LED position while (1) { // Loop forever opt_test = get_counter(); opt_test++; put_counter( opt_test ); } // end while
(Note: this was just tacked onto the "Timer" project to try things out)
What I get: Build target 'MCBSTM32' assembling STM32F10x.s... creating preprocessor file for STM32_Init.c... compiling STM32_Init.c... creating preprocessor file for Timer.c... compiling Timer.c... creating preprocessor file for optimize.c... compiling optimize.c... linking... .\Obj\Timer.axf: Error: L6218E: Undefined symbol get_counter (referred from timer.o). .\Obj\Timer.axf: Error: L6218E: Undefined symbol put_counter (referred from timer.o). Target not created What I have tried: Compiled with optimization levels of 2 and 3.
Is this functionality actually working? If so, is there anything I should be looking out for that might cause this error?
You might have missed how inlining work.
The compiler can not inline a function unless it sees the implementation of the function.
So, to inline the code you need to place the function in the header file, and not in the c file. But that kind of breaks your goal to isolate the accesses...
In your case - when you use the __forceinline attribute, then the compiler knows that the function will always be inlined. Because of this, the compiler need not create one copy of the file with external binding.
When compiling the other c file, the compiler does not see the implementation of the function, so it must create code trying to access an externally linked function.
In the end, the linker has one object file trying to access an external reference but no object file that exports such a function.
Obviously it works different than C++ then.
I know I can have an inline function in a .C++ file and declare the call to it in the C++ class, which is similar to my example.
Are you then saying that, in this instance, the implementation of inline operates in the same mode as a #define macro?
Are you also stating that there is no means to encapsulate except with explicit function calls and there is no way to optimize out the function call?
Are you really sure?'
When you define an inline function, the compiler will still create one "normal" instance of the function unless it knows that the function is only visible in a single source file and knows that all calls have been inlined.
When the compiler sees the implementation, and thinks that it is good to inline, then it will inline. If the compiler doesn't see the implementation, or decides that the function contains any constructs that are not suitable for inlining, then it will instead create a call to the function.
In short, unless you create a list file or single step the code, you will not be able to see if your C++ compiler has inlined the function or not.
There are a few compilers who can wait with the code generation for templated functions until link time. In that case, the compiler will basically copy the source code for the template function to the object file or to a specific stash, where the linker can pick up the information and figure out exactly what instances that needs to be created. I know this concept exists for template functions, but I'm not sure if there exists any released C++ compiler with similar behaviour for inlined functions. If you know about any, plesae post that information.
Ok, you got me. I just ran an example and the inline functions had to be in the include file along with the class declaration.
Man I hate it when I misremember so definitely! ;-)