Author Topic: c vs cpp for stm32  (Read 7693 times)

0 Members and 1 Guest are viewing this topic.

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 51
  • Country: ro
Re: c vs cpp for stm32
« Reply #25 on: January 13, 2019, 07:41:19 pm »
Oh boy, this argument again! Apparently I can get my annual rant on this topic out of the way nice and early in 2019.

Folks need to remember that C is, essentially, a portable Assembly language. It was designed and intended to be a "mid-level" language, trading a bit of Assembly's efficiency for portability across platforms. There's a lot of value in that tradeoff, because it allows the investment in debugged code to be migrated to different/new hardware/OS environments. And the industry has responded, resulting in some processors having their instruction sets specifically optimized for C language constructs - making it easier for compilers to generate efficient code from C source.

But, as with virtually every discipline (hardware, software, mechanical, even the design of governments [I'm thinking of you, US Constitution]), when you insist on glomming a bunch of later features that go way beyond the scope of the original intent, you get "spaghetti code". The glommed-on features are usually poorly implemented and awkward to use. Meanwhile, they often conflict with the original architecture and interfere with some/all of the original features. A nice lose-lose arrangement.

Consider two examples:

1) C++. I'm sorry, but the best feature of C++ is its // comment operator so you don't have to terminate comments with */. If you don't hate C++, you haven't debugged something like overloaded functions written by strangers you've never met. In what universe is it a good idea to have multiple entities share the exact same name? A call to an overloaded function name means you don't really know where your code is going. Good luck if those overloaded functions are in some library for which you don't have the source. And I can't imagine a sufficiently painful punishment for whomever added dynamic polymorphism, where you literally don't know and may not even be able to predict what functions will be called when, now or in the future! I realize this sort of thing replaces normal sexual excitement for Computer Science postdocs, but in the real world these sorts of language "features" literally enable bugs and exploits that are hideously difficult to find and fix. I can't prove this, but after lots of conversations I'm convinced that the obtuseness and opacity of environments like C++ cause Engineers to just throw up their hands and declare something "done" because there's simply not the time nor money nor management support to find and test the edge cases. And C++ *creates* such edge cases, as when user input can basically randomize your execution path (choice of called function dependent upon what the user types now/today/next week). It's entirely possible that the first "real user" will invoke function(s) never before called during alpha and beta testing, with unknown and untested results. Insanity! C++ insures perpetual profitability for the antivirus industry.

2) Java. Sort-of-C, sort-of-C++, with yet another layer Rube Goldberged into the mess. Every time you turn around there's another weird special case that is painfully and obviously due to the effort to add something that doesn't quite "fit" with the base language. I'll admit functions like BigDecimal() are handy, but there's nothing Java-specific about that. If Object Orientedness is the goal, use a language designed from the ground up with that in mind. There's no shortage of them out there... why hobble yourself with some hybrid, bastardized FrankenLanguage like Java?

I'm sure I've offended some folks with the above. But after ~40 years of writing software and firmware in all sorts of OS and embedded environments, these are my conclusions. Yours may vary, and that's fine, but I've reached the point in my career where I can turn down projects that are artificially handicapped because someone demands we use their favorite OO-hybrid language to implement an LED flasher. Wrangling projects to successful completion is hard enough without intentionally lashing oneself to such an anchor. Tools are supposed to make jobs EASIER, not more difficult.

Just my $0.02, and worth no more than you paid for it! {grin}
Can you tell as in OS you have worked, is it used the C++,? I know in Linux kernel, C is used.


Sent from my VTR-L29 using Tapatalk

 

Online Yansi

  • Super Contributor
  • ***
  • Posts: 3259
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: c vs cpp for stm32
« Reply #26 on: January 13, 2019, 07:44:30 pm »
So there are pro and cons for c++. When starting a new project on a powerfull stm32f7xx series microcontroller do you consider C++? Do you try to reuse code from PC world to micro?

Sent from my VTR-L29 using Tapatalk

Not even remotely considering C++.   Most things in real world even can't be written in it, due to safety concerns of the C++ being less predictable and harder to be statically analyzed for possible errors.

STM32F7 can be written in C no problems.

And yes, I have used some interesting pieces of "PC code" in them, for example have ported the Nuklear graphics library in there. https://github.com/vurtun/nuklear Wasn't even complicated, I have even let it do it's magic with dynamic allocation, haven't bothered to reconfigure the examples provided. Have worked absolutely fine.
 
The following users thanked this post: bogdant

Offline rhb

  • Super Contributor
  • ***
  • Posts: 2815
  • Country: us
Re: c vs cpp for stm32
« Reply #27 on: January 13, 2019, 11:06:53 pm »
My experience working on several million lines of other people's code is that old C & FORTRAN codes can be fixed even if there is no documentation or comments if you understand what they do.  It can be painful if you have to read a professional paper to determine if the calculation is being done in the time or frequency domain, but it can be done.

The two old C++ codes I was asked to look at could not even be compiled.  In one instance the developer had deleted all his files when he was laid off and put a logic bomb in the code.  I had his machine and account restored from backups but even with his command line history and environment I couldn't get it to compile.  The command line history suggested that he had great difficulty compiling it himself.

Fortunately the logic bomb used system( "date" ) to get the date for triggering the logic bomb.  So I just put a wrapper around the program that used a one line shell script to lie about the date.  That bought me time to find a commercial replacement.

The other instance, the code was so old that no C++ compiler would accept it. I tried quite a few, but there was either no extant executable or it had been stripped so I couldn't identify what that author had used. I did work out that it was written before the C++ standard was ratified using some version of g++, but that was all.
 
The following users thanked this post: bogdant

Offline ehughes

  • Frequent Contributor
  • **
  • Posts: 383
  • Country: us
Re: c vs cpp for stm32
« Reply #28 on: January 13, 2019, 11:28:08 pm »
For me it is pretty easy,  always C.      By the time I need the abstractions that c++ provides, I find that there are other high level languages that do it better and offer real memory safety, etc.

For most embedded work I have never seen the need for reuse that c++ claims to offers.      Virtually all embedded systems require integration between the software pieces and the idea that you will ever wholesale reuse something without modification is dumb.    It is a waste of time abstracting everything.   

I was once told to use c++ for the Lambda's.   It looked like the dumbest idea ever for embedded code.   

I was also shown (by a CMU professor at a conference) that C++ can overlay objects on memory mapped peripherals.   It was the ugliest boiler plate I have ever seen for initializing a UART.  He claimed you will never make a mistake using of using signed int pointer for a peripheral registers.       Seemed like a lot of work for software purity.


I honestly find myself wanted to go the other way.    If I want to write cryptic code,  I'll just do it nice and tight in asm.

 
The following users thanked this post: bogdant

Offline 17_29bis

  • Regular Contributor
  • *
  • Posts: 81
  • Country: ca
Re: c vs cpp for stm32
« Reply #29 on: January 14, 2019, 12:52:44 am »
Quote
specifically the ones that could not be done in C
There is nothing that can be done in C than cannot also be done in assembly. I assume you don't program in assembly. The same applies to C++. You pick a language because its easier/more reliable/better in some way than any previous language you were using.

The question was actually for a different user but hearing different opinions is always good. As far as I am concerned I know Assembler, C, C++, Python and have been doing contract work using those languages for years. The reason why  I asked the question what I asked is simple. There are different projects, some can be implemented/written (more or less) in any computer language, some require specific language and some may benefit from using a particular computer language more then other etc.

My 0.3 cents: main difference between C++ and C is that C is a procedural language and C++ is  all about OOP (Object Oriented Programming). If your project does not require OOP  when why invent a square wheel? if you know Assembler, C - use it and it will pay off in a form of more easy support and debugging, otherwise you still can use C++  and get the job done.  If  your project does require OOP then I would say - try to study C++ instead of developing the code in C  (which is also possible to some extended but it will require enormous efforts).

PS: looks like I simply restated in my own language what cv007 said above in his last sentence.

 
The following users thanked this post: bogdant

Offline IDEngineer

  • Frequent Contributor
  • **
  • Posts: 907
  • Country: us
Re: c vs cpp for stm32
« Reply #30 on: January 14, 2019, 01:00:48 am »
I was also shown (by a CMU professor at a conference) that C++ can overlay objects on memory mapped peripherals.   It was the ugliest boiler plate I have ever seen for initializing a UART.  He claimed you will never make a mistake using of using signed int pointer for a peripheral registers.       Seemed like a lot of work for software purity.

Sounds very familiar, right in line with my comment about CS postdocs above. Those guys get sweaty palms about this stuff, but in the real world of actually shipping products the "purity" of it all matters less than getting it done and knowing it's correct.

I didn't make up that "sweaty palms" comment, by the way. That's a direct quote, describing himself, from a CS professor who came to teach an OO class at one of my former employers who had been convinced by the local university that OO was the future. Their team of Project Engineers, of which I was one, sat through about the first week of his classes and then informed management they could have OO only if they were willing to double every development schedule going forward to accommodate this latest fad d'jour. The class ended abruptly soon after. It was valuable, though, for revealing the true motivation behind OO for some of these people. AFAIK this professor (who was a very nice individual, BTW) had never shipped an actual product in his life, so he and his fellows could afford to wallow in the latest craze getting their [insert body part here] sweaty. Meanwhile, we were writing embedded firmware in C and Assembly, languages which are broadly supported on virtually every platform and which are generally the very first (and sometimes only!) languages to be supported on new hardware. True then, true today.
« Last Edit: January 14, 2019, 01:02:54 am by IDEngineer »
 
The following users thanked this post: bogdant

Online Mattjd

  • Regular Contributor
  • *
  • Posts: 204
  • Country: us
Re: c vs cpp for stm32
« Reply #31 on: January 14, 2019, 01:29:59 am »
a lot of you guys keep saying C++ and java (more C++) dont get used in deployment code but I work for one of the largest defense contractors in the world and I can tell you that after my department is done (the modeling and simulations part) the deployment is done in C++ and java.

So, what are you guys talking about? Or are you just painting broad strokes?
 
The following users thanked this post: bogdant

Offline bson

  • Supporter
  • ****
  • Posts: 1640
  • Country: us
Re: c vs cpp for stm32
« Reply #32 on: January 14, 2019, 02:22:39 am »
Double check your linker script and startup code integrate properly with the C++ runtime.
I'm not on my dev machine at the moment but I'm quite certain my linker script had to add additional sections to store constructors for static objects and so on, and startup code to call those constructors during runtime initialization - at a guess I'd say your hard fault is possibly related.
That's not really true anymore for the gcc toolchain; it uses the static initializer list for things like initializing the data segment from flash.  These used to have a separate table, but it's now unified.  In the process, the .ctor.* and .dtor.* (I may misremember the exact prefix used) also disappeared and there is now a single static initializer.  As a result, neither the linker script verbage to collect and emit the list (which must be a pure section) or the code to walk the list is optional.  If you don't use ANY standard library you need to provide it yourself and make sure it gets called early, or your data segment will be uninitialized prior to reaching main().  Of course, the destructor lists don't need to be kept, since firmware isn't a normal program that will ever exit, so no need to keep things like destructors for global objects.

Code: [Select]
// In a compiler specific header
// #define __weak gnu::weak

[[__weak]] extern void (*__preinit_array_start []) (void);
[[__weak]] extern void (*__preinit_array_end []) (void);
[[__weak]] extern void (*__init_array_start []) (void);
[[__weak]] extern void (*__init_array_end []) (void);

void init_array() {
    size_t count, i;
   
    count = __preinit_array_end - __preinit_array_start;
    for (i = 0; i < count; i++)
        __preinit_array_start[i]();
   
    count = __init_array_end - __init_array_start;
    for (i = 0; i < count; i++)
        __init_array_start[i]();
}
 
The following users thanked this post: bogdant

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 892
  • Country: us
Re: c vs cpp for stm32
« Reply #33 on: January 14, 2019, 04:06:14 am »
GCC's linker generates a function to do all the static initialization: __libc_init_array(). I don't rely on static initialization these days, but still include a call to it in Cortex-M reset handlers:

Code: [Select]
#include <cstdint>

extern "C" {

extern uint32_t __etext;
extern uint32_t __data_start__;
extern uint32_t __data_end__;
extern uint32_t __bss_start__;
extern uint32_t __bss_end__;

extern int main();
extern void SystemInit();
extern void __libc_init_array();
 
void Reset_Handler() {
  SystemInit();

  uint32_t *src = &__etext;
  uint32_t *dst = &__data_start__;
  uint32_t *lim = &__data_end__;

  while (dst < lim) { *dst++ = *src++; }

  dst = &__bss_start__;
  lim = &__bss_end__;
  while (dst < lim) { *dst++ = 0; }

  __libc_init_array();

  main();
}

} // extern "C"
 
The following users thanked this post: bogdant

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 51
  • Country: ro
Re: c vs cpp for stm32
« Reply #34 on: January 14, 2019, 06:29:02 am »
Is there a way to evaluate an micro based project needs OOP?
 

Offline Berni

  • Super Contributor
  • ***
  • Posts: 2766
  • Country: si
Re: c vs cpp for stm32
« Reply #35 on: January 14, 2019, 06:35:33 am »
Yeah i like to stick to C. I do like some of the extra features that C++ provides but i never end up using any of the more advanced stuff such as lamba functions and just stick to classes and overlays.

Object oriented programming is not all bad, the problem is that programmers take the idea way too far. They are often taught straight C++ without showing them C or assembler beforehand so they have no idea whats going on under the hood. Then the go and make classes for every little thing you could think of, inherit them 10 levels deep, give them confusing names, use factories to create them etc.. Its mostly the programmers fault for why C++ code tends to become messier than C code even tho object oriented programing is supposed to make cleaner code. For the rare times you want class like behavior in C you can use a struct and pointers to do pretty much the same thing (It looks a bit worse tho).

But just because you stick to C doesn't mean you can't make a tangled mess of code. The STM32 HAL libraries are a good example of it. The thing was clearly made by a C++ programmer that was forced to use C by there boss. There are so many structures everywhere for no reason, #includes drag in all sorts of crap. The #define macros used nest other defines inside of them over 5 layers deep, these defines are scattered all over a pile of .h files. Its a real puzzle combined with a cat and mouse chase to find out what one of these #define actually does (And they use a lot of fancy tricks too so you better be sharp on your operators and pointer tricks). It should not be this difficult to figure out how a damn UART or GPIO driver works. To add insult to injury the HAL drivers sometimes don't work so you have to actually go and debug this mess, or sometimes the driver is designed for a weird use case where you need to actually modify it to make it do what you need.(Like the UART driver can't continuously receive or the I2C driver can't generate a bus restart condition)

Here is an example how a C++ programmer can turn a perfectly sensible piece of code into object oriented shit:
« Last Edit: January 14, 2019, 06:38:08 am by Berni »
 
The following users thanked this post: sorin, Siwastaja, bogdant, genghisnico13, nick_d

Offline Vasi

  • Regular Contributor
  • *
  • Posts: 60
  • Country: ro
    • Visual Pin Configurator for Nucleo L152RE - produces SPL code.
Re: c vs cpp for stm32
« Reply #36 on: January 14, 2019, 06:42:46 am »
The target is not the language. And you are not tied to that. If you are asked to do a job, you do it based on your knowledge. And the result can be brilliant of very poor, no matter the language used.
 
The following users thanked this post: bogdant

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1603
  • Country: fi
    • My home page and email address
Re: c vs cpp for stm32
« Reply #37 on: January 14, 2019, 07:40:55 am »
Does it make any sense to switch from c to c++?
It makes exactly as much sense as switching from German to French.

If you live in France (say, intend to use existing Arduino code), then yes.  If you live in Germany (say, have a large C codebase), then probably not.

It is a good idea to learn new programming languages, at least to the point that you can solve typical problems for that language using robust, clean, easily maintained code.

The reason for that is that tool choice affects how the maker thinks.  I believe that most (good?) programmers eventually think in an internal non-verbal language they use to manage the inherent complexity in large software projects.  Learning different programming languages (and the more different, the better; consider exploring Haskell and Lisp, if only to see if you can grasp how they could be useful) allows a better "vocabulary" for that internal language.  C and C++ are too close to really force one to understand their differences. It is like being an orange farmer, and being asked to describe a lemon, or how a lemon differs from an orange.  Or maybe a lime and lemon, I dunno. Fruits all the way.

I used to write user interfaces in C++, but I seem to have shifted to Python for that. (The biggest reason for that is probably that I like having the user interface user-modifiable without recompilation or having a development environment.) The object-oriented paradigm is perfectly suited for those.

I use C for low-level libraries and high-performance computing core routines, as writing them in assembly would be too slow. (I can do that too, though; it is just that outside of SIMD vectorization, current C compilers typically find optimization opportunities at the machine code level I would miss.  For critical code, I still do some inline assembly, but even for those, I tend to start by looking at different variations generated by a C compiler, then try to better that.)

For microcontrollers, I use a strict imperative subset of C++; no exceptions, and objects more like syntactic sugar used to keep the code modular.

For microcontrollers, the Arduino environment is one big trove of usable and not-so-usable code, and it is written in a subset of C++.  In C, when writing modular or library code, there is really only one global namespace, so naming the interface functions and objects is rather critical. Typically that means having a prefix (or suffix) of the library name as part of the name, which is a bit annoying.  In C++, classes provide a nice namespace separation, and makes combining C++ code from different sources easier.  The only trick, really, is to find out what that subset of C++ exactly is.  It has no strict boundaries, because different microcontroller environments provide slightly different subsets of C++.

So, really, the real-world discussion should not be whether one should switch from C to C++ when working with microcontrollers, but which subset of C++ is appropriate for which tasks, and in which cases e.g. freestanding C is more appropriate instead.  Unfortunately, we'd need to talk about that openly all the time, because it depends on so many variables (hah; I mean, compilers and libraries and hardware change constantly, at a rather rapid pace); but all discussions on this I've seen eventually degrade into worthless bickering and bikeshedding.
 
The following users thanked this post: legacy, bogdant

Offline shangaoren

  • Contributor
  • Posts: 34
  • Country: fr
Re: c vs cpp for stm32
« Reply #38 on: January 14, 2019, 10:20:28 am »
I'm working on embedded systems, our company is partner with STMicroelectronics, we use a custom RTOS that is designed in C++, i wrote my own open source RTOS in C++.
If you take care of what you do, C++ is not more messy than C, it's just the language that give you more possibilities, so more possibilities to do crap.

I will never go back on my own to C because of templates, references instead of pointers, overloading, and object oriented by examples, the code is more easy to read, references can avoid many errors.
With modern tools C++ isn't that hard to debug if you know what you do.
A well written C++ code can be more efficient than C or assembler one, we have a fully autonomous drone than run with a cortex M4 spending 70% of his time in idle state.

If you need to know what's going on under the hood have a look at this : https://godbolt.org/


If you want to try C++ in embedded, go for it, as long as you know what you are doing everything would be fine, you will be able to do all the things you wants in Assembler/C or C++ but for me C++ is much more handful.
When you want to go somewhere, you can walk, go with a bike, or with a car, the result will be the same but you will not need the same amount of time ;)
 
The following users thanked this post: legacy, bogdant

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 51
  • Country: ro
Re: c vs cpp for stm32
« Reply #39 on: January 14, 2019, 11:04:05 am »
What subset of C++ will be useful for microcontrollers?
Comming back to the problem I am facing: I add the .ctor and .dtor in the linker file, but in map file the sections are empty. I am missing something here.

Here is the options compiller called

.....
Building file: ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c
Invoking: MCU GCC Compiler
C:\myfiles\radio103\firmware\radio\Debug
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -std=c11 '-D__weak=__attribute__((weak))' '-D__packed=__attribute__((__packed__))' -DUSE_HAL_DRIVER -DSTM32F103xE -I"C:/myfiles/radio103/firmware/radio/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3" -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Device/ST/STM32F1xx/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FatFs/src" -I"C:/myfiles/radio103/firmware/radio/Drivers/lcd"  -Og -g3 -Wall -fmessage-length=0 -fno-verbose-asm -ffunction-sections -c -fmessage-length=0 -MMD -MP -MF"Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.d" -MT"Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.o" -o "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.o" "../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c"
Finished building: ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c
.....
arm-none-eabi-g++ -std=c++1y '-D__weak=__attribute__((weak))' -DSTM32F103xE -DUSE_HAL_DRIVER '-D__packed=__attribute__((__packed__))' -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Device/ST/STM32F1xx/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FatFs/src" -I"C:/myfiles/radio103/firmware/radio/Drivers/lcd" -I"C:/myfiles/radio103/firmware/radio/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Device/ST/STM32F1xx/Include"  -Os -g3 -Wall -c -fmessage-length=0 -fno-verbose-asm -MMD -MP -MF"Src/Radio.d" -MT"Src/Radio.d" -o "Src/Radio.o" "../Src/Radio.cpp"
Finished building: ../Src/Radio.cpp

Invoking: MCU G++ Linker
arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -specs=nosys.specs -specs=nano.specs -T"../STM32F103RETx_FLASH.ld" -Wl,-Map=output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "radio.elf" @"objects.list"   -lm


The build is finished with success.
I use gcc in System Workbench STM32 / WinIdea Open/J-link/Custom board with stm32f103.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: c vs cpp for stm32
« Reply #40 on: January 14, 2019, 11:05:32 am »
I am writing, just right now, polymorphism in C :D

##It
#can
##be
done

(funny, or odd?, that is the problem)
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: c vs cpp for stm32
« Reply #41 on: January 14, 2019, 11:07:06 am »
it's just the language that give you more possibilities, so more possibilities to do crap.

 :clap:
 

Offline shangaoren

  • Contributor
  • Posts: 34
  • Country: fr
Re: c vs cpp for stm32
« Reply #42 on: January 14, 2019, 11:26:23 am »
it's just the language that give you more possibilities, so more possibilities to do crap.

 :clap:

Just as every languages no news here, the crap came from the man who do the code, not the language ...


I am writing, just right now, polymorphism in C :D

##It
#can
##be
done

(funny, or odd?, that is the problem)


you can cut a tree with a knife too, but why would you do that ?
« Last Edit: January 14, 2019, 11:32:41 am by shangaoren »
 

Offline shangaoren

  • Contributor
  • Posts: 34
  • Country: fr
Re: c vs cpp for stm32
« Reply #43 on: January 14, 2019, 11:37:18 am »
What subset of C++ will be useful for microcontrollers?
Comming back to the problem I am facing: I add the .ctor and .dtor in the linker file, but in map file the sections are empty. I am missing something here.

Here is the options compiller called

.....
Building file: ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c
Invoking: MCU GCC Compiler
C:\myfiles\radio103\firmware\radio\Debug
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -std=c11 '-D__weak=__attribute__((weak))' '-D__packed=__attribute__((__packed__))' -DUSE_HAL_DRIVER -DSTM32F103xE -I"C:/myfiles/radio103/firmware/radio/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3" -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Device/ST/STM32F1xx/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FatFs/src" -I"C:/myfiles/radio103/firmware/radio/Drivers/lcd"  -Og -g3 -Wall -fmessage-length=0 -fno-verbose-asm -ffunction-sections -c -fmessage-length=0 -MMD -MP -MF"Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.d" -MT"Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.o" -o "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.o" "../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c"
Finished building: ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.c
.....
arm-none-eabi-g++ -std=c++1y '-D__weak=__attribute__((weak))' -DSTM32F103xE -DUSE_HAL_DRIVER '-D__packed=__attribute__((__packed__))' -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" -I"C:/myfiles/radio103/firmware/radio/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Device/ST/STM32F1xx/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Include" -I"C:/myfiles/radio103/firmware/radio/Middlewares/Third_Party/FatFs/src" -I"C:/myfiles/radio103/firmware/radio/Drivers/lcd" -I"C:/myfiles/radio103/firmware/radio/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc" -I"C:/myfiles/radio103/firmware/radio/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy" -I"C:/myfiles/radio103/firmware/radio/Drivers/CMSIS/Device/ST/STM32F1xx/Include"  -Os -g3 -Wall -c -fmessage-length=0 -fno-verbose-asm -MMD -MP -MF"Src/Radio.d" -MT"Src/Radio.d" -o "Src/Radio.o" "../Src/Radio.cpp"
Finished building: ../Src/Radio.cpp

Invoking: MCU G++ Linker
arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -specs=nosys.specs -specs=nano.specs -T"../STM32F103RETx_FLASH.ld" -Wl,-Map=output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "radio.elf" @"objects.list"   -lm


The build is finished with success.
I use gcc in System Workbench STM32 / WinIdea Open/J-link/Custom board with stm32f103.



I don't understand your problem, you don't need to modify the linker script, in the startup there is a function with a name like "__libc_c_init_array" or something like this, this function is here to call your ctor. you don't need to have dtor unless you use dynamics instantiation which is not a good idea in an embedded system
« Last Edit: January 14, 2019, 01:54:48 pm by shangaoren »
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 1603
  • Country: fi
    • My home page and email address
Re: c vs cpp for stm32
« Reply #44 on: January 14, 2019, 11:46:26 am »
A well written C++ code can be more efficient than C or assembler one
You do realize that claim is completely preposterous, or a straight lie?  That is exactly the kind of argument that has negative value in a serious discussion.

Nothing can be more efficient than assembly code, because is is just an exact representation of the machine code compilers generate.  Sure, you're going to weasel out of that by claiming that you meant something else, like if you compare the C++ code to the C or assembly code you or your colleagues write, but that's like me saying that English is a poor language because I can express myself in Finnish more clearly and with more finesse.  It is an idiotic argument, and exactly the kind of shit that drives me crazy.

That kind of crap might fly here, but it really is like claiming that those $5000 digital audio cables do sound better, because the ones and zeros have better fidelity on those cables.

(No need to say anything, Simon; I'll shut up. I tried to avoid this thread, but failed.)
« Last Edit: January 14, 2019, 11:48:09 am by Nominal Animal »
 

Offline Berni

  • Super Contributor
  • ***
  • Posts: 2766
  • Country: si
Re: c vs cpp for stm32
« Reply #45 on: January 14, 2019, 12:08:22 pm »
That depends on who is writing assembler. Of course C++ can't be faster than the optimal assembler code. But do mortal programmers write optimal assembly code every time?

I think C++ with the right optimization flags tends to generate more efficient code than what you would get if you have someone write it directly in assembler. Over time C compilers have become pretty smart at optimizing code on the widely used architectures, so the machine code that pops out is pretty close to optimal (Given optimal C code was fed to it). A human writing assembly code is likely to miss some optimization opportunities or skip over ones that are particularly annoying. A experienced assembly programmer that has great understanding of the architecture can write really optimized short snippets of code, but once the piece of code becomes larger and more complex it gets a lot more difficult for a human to keep pace with a C compiler.

The general idea is that optimal C code is easier to write for a human compared to optimal assembler code. But C can usualy convert optimal C code into near optimal machine code while large blocks of hand written assembler are a lot of work to write and harder to maintain later on.

So for most real world cases C++ is indeed faster than assembler once you consider realistic human factors. These human factors are only exaggerated even more once the typical tight deadlines start to rain down from upper management on the said human.
 
The following users thanked this post: shangaoren

Offline Otatiaro

  • Regular Contributor
  • *
  • Posts: 85
Re: c vs cpp for stm32
« Reply #46 on: January 14, 2019, 12:12:31 pm »
Hello,

I will focus only on embedded C++ (mainly on STM32 for my experience), for PC development I use mainly C#.NET.

From my point of view there is 3 categories of persons about this subject:
1 - people who will not use C++, ever, because they love C, they love the way they work (forgive me but I depict them as using VI for code editing, launching compiler with command line and debugging with LEDs/UART ... a bit caricatural I know, but sometime not so far from reality). I won't try to convince them to switch to C++, not even to try it out, because they are convinced C++ is bloaty, that OOP leads only to bad code, and technical reasons so out of date or utterly wrong (no an object does not have pointers on all it's members functions ... it MAY have a vtable for certain virtual methods, depending on the compilation options and many other parameters) that it's not even a debate, it's talking to walls.
2 - people who already use C++ when they can. They already know why they use it, so I guess we can share ideas, tips and tricks, but I don't have to convince them anymore.
3 - people that use C because "isn't it what people use for embedded ?", who already use "modern" tools (IDE based Eclipse or visual studio, a real debugger with fancy options like stepping, breakpoints, memory analyzers, etc.), and who wander why would they use C++ in addition to C. Those are my target today, if I do my job correctly they will try it, maybe not like it and revert to C, but I'm pretty sure some of them will discover a new world of possibilities.

That being said, why and more importantly HOW would you use C++ for embedded development ?

First you have to understand language is only a tool. You can do wonders with inadequate tools if you are very experienced, but a good tool makes the job easier.
Reminds me a cartoon I used to read when I was young "Leonard : genius", where he sees woodcutters using a manual saw to cut a tree, he first give them a chainsaw but forgot the gas to put in, so he go get some gas and when he come back the woodcutters are using the chainsaw as a manual saw, complaining it is heavier and does not cut as well as their manual saw ...
That's the main point for C++, it's a very efficient tool if you learn how to use it, and use it right :
- C++ is not OOP C
- embeddded C++ is not desktop C++
- I'd say there is not one C++, there are as many C++ as developers or teams of developers using it

What we don't use in embedded C++:
- exceptions : an embedded program is often structured as "init then while true do always the same thing again and again", you should handle error cases, not rely on exceptions that are useful only on high end OS like windows or linux.
- reflexion : same reason, in embedded you don't load code dynamically, everything is known at compile time, so there is no use for reflexion (RTTI or Real Time Type Information)
- dynamic allocation : again, almost everything is known at compile time, and memory is very limited compared to a PC, so almost everything should be statically allocated, and data with unknown (but bounded) size be allocated in specific, dedicated buffers
Most of the embedded C++ tools I know of disable exceptions and RTTI by default, so you don't have to care about it. Dynamic allocation is permitted by default, our framework overrides the default "new" with an error, so that you know you should not use the default new (you can still override it for specific purpose).

Encapsulation is the ability to specify what part of your object is accessible from the outside. If you look at a C struct, what field can I change directly, what should be changed by using a function (and where is this function's code anyway ...) ? In C++ you describe your object, it's inner working, and the interface, i.e. how should people or other objects interact with your object. When you work as a team, and you need to code some classes for someone else, you first define the interface, it makes things so much easier, and then you can change the inner working of your class, he can change how he uses your class, without any breaking change. C has everything accessible, so either you are working alone and know what to do and not to do, or you will need to write extensive documentation about how to use your struct, when you can change the fields directly or need to go through accessors, etc.

Because of the dynamic allocation, you also will not use many of the provided STL data structures because they are targeted at PC development and heavily rely on dynamic allocation (yep, no vector allowed here ...).
But the good thing is you will write your own data containers, once. Want to use linked lists ? Write a template, debug it and you're done, no need to write it again.
Templates gives the ability to describe features or concepts, that do not depend on the underlying type : how a list works does not depend on the list item type ... an integer list works the same way as a float list, or a list of objects.
Code once, debug once, use it for free for the rest of your life.

Virtual methods are cheap performance wise. Worst case it is an additional dereference (through the vtable), but in many case the compiler will know at compile time what is to be called and will optimize it for you. What are virtual methods ? A way to link an object to a specific member function (in case two objects should call different code for the same method), of course you can do it in C (there is nothing, output wise, that can be done in C++ that cannot be done in C), but then you will have to handle the vtable yourself, update it, make use of it manually, etc. C++ compilers does the same, except with a simple keyword you can tell it to do the work for you. You may not understand why it is so useful right now, but there is a point where you face a problem, and having a pointer to the code in the object itself is the solution ... C++ already have the tools available for you.

C++ is a modern programming language. There is C++17 (2017) currently implemented in most compilers, and C++20 (2020) will probably have concepts, which will be awesome. C++ improves on new features, sure, but also a lot on making it easier and simpler. C ... well, last C standard is C99 ... yes, 1999.

In many case, simple C++ is simpler and faster than C. Ok let's take a very simple exemple, I want to create a buffer of 30 bytes and fill it with a specific value (say 0x55), let's see how to do it in "simple C" (some would say simplistic C), in "simple C++", then in "advanced C" and "advanced C++":

Simple C:

uint8_t buffer[30];
uint8_t i;
for(i = 0; i<30; i++)
buffer = 0x55;

Simple C++:

std::array<uint8_t, 30> buffer;
buffer.fill(0x55);

Let's compare them:
- lines of code : 4 lines vs 2 lines. Well yeah you could
- readability : yeah a simple for loop is not that hard to understand quickly for an experienced developer ... but agree that buffer.fill is more expressive, no ? You don't have to understand what it does looking at the code, it's self-describing ...
- performance : I tested it on Atollic, running it on the actual STM32, the C++ version is MUCH FASTER than the C version. Why ? Because by default array.fill can optimize much more than the for loop (STM32 is a 32 bit platform, so fill will transfer 32 bit at a time instead of 8, and also move multiple 32 bit registers at a time to maximize throughput).
- bug-prone : how many times does C++ repeat the buffer size ? None. Whereas the C code duplicates the "30" magic number, so there is a chance you change the buffer size later and forget to change the for loop condition, ending in memory corruption. Ho and by the way, what happens in C code if I change the buffer size to 300 ?
- memory : it is the EXACT SAME result on both, they use only the required memory space, that is 30 bytes. But then you will ask, how the hell does fill knows the buffer length ? It is a sort of "compiler only" variable, that the compiler know, but that will not take space in memory if not needed.


Now I hear some C dev shouting at me, saying that is not good C and nobody writes such code. From my experience, the vast majority of C developers write this type of code.
But let's see the "advanced" version, something a more experienced C or C++ developer would probably write:

Advanced C:

uint8_t buffer[30];
memset(buffer, 0x55, 30);

Advanced C++:

std::array<uint8_t, 30> buffer;
buffer.fill(0x55);

Let's compare them:
- Yes, read it again ... the "advanced C++" is the exact same as "simple C++", I even copy-pasted it to make sure it was exactly the same.
- C is now 2 lines of code, same as C++
- readability : well, memset of not that bad, let's say it's a tie even if I think fill is more meaningful.
- performance : I'll be honest, from my tests C was just a bit faster (a few percent at the very best) depending on the compiler options. So that's a point for C, that I would mitigate because on the simple case C was many times slower than C++ (not a few percent), and just because you still can write the C version in C++ and get the same performance in case you really need the extra clock cycles (but then I'm pretty sure you can optimize a lot more somewhere else in your code...)
- bug-prone : C still repeats the buffer size, but at least memset uses a 32 bit index by default
- memory : same as before

What I want to show you is C++ is easier to write "good / not so bad" where beginner C developers often use bad behaviors. Why ? In C you have to search for the memset function, understand how it works, if you don't know it exists then you will use the for loop. In C++ if you have the right tool, you just type ctrl-space and you are presented with the possibilities ... there is a fill function on a buffer ? does it do what I expect (you still need to write documentation, but far less) ? yes ? then just use it and get 98% of the performance I'd get using advanced C (and many times faster than simplistic C).

Also not repeating the buffer size is one of the major, if not the best, feature of C++. Contrary that what some may say, C++ is not bloaty but it has plenty of tools to make lighter code size / memory footprint / code performance.
One of them is the constexpr keyword, constexpr tells the compiler it may have everything at hand to compute the result of some arbitrary code, and then it should do so (compute the result at compile-time, not at runtime).
Compilers do that kind of optimization for years, even in C, but you have absolutely no way to tell the compiler you want it to be that way. With constexpr you can both ask the compiler to compute at compile-time, and ask it to enforce that it can compute it at compile time (so that you cannot modify the code in a way it's not anymore and you loose runtime performance without knowing why). What if you don't use constexpr in C++ ? Well you get the same behavior as C, if the compiler can optimize, it will ... maybe, maybe not.
And constexpr variables do not use memory in the final binary code !!!! You can define HUGE constexpr variables in embedded code, it will not use any of your few kB of RAM, it will only use a small portion of your multi GB PC RAM.

So what you will be using extensively when switching from C to C++ in embedded projects:
- constexpr to make as much as possible your PC do calculation instead of your small microcontroller.
- templates to reuse data structures as much as possible, writing less code (and less code means less bugs)
- public / private to show only what you want of your object
- at some point you will probably face problems that have good solutions built in C++ (virtual methods, std::function, lambdas, etc.) At least as good as what you would do as an experienced C developer, except the compiler does part of the job for you, if you drive it correctly.

Here in my team we develop for embedded in C++ for a few years. We developed our own in-house RTOS for Cortex-M(3/4/7), our own framework of data structures, drivers and devices that we can reuse on all projects.
We have been invited in the ST partner program last year and we are in tight discussion with ST about this subject, we plan to make seminars/webinars on this subject too (at first in French, sorry), and they are still amazed at the performance we get out of their controllers, even compared to very experienced C programmers/teams.
And ask my team members about it (@shangaoren is one of them), they really embraced the C++ way of thinking and clearly see why we use it.

If I managed to get you interesed in the subject (YES !), then here is a few resources that you may find vey helpful:

- https://godbolt.org/ compiler explorer, this tool is so nice to understand what the compiler does under the hood, and it includes ARM Cortex-M compilers. So helpful to understand the effects of optimization flags, etc.
- about constexpr, and especially this one shows C++ is also targeted at very small platforms with efficiency in mind.
- The cppcon talks : https://www.youtube.com/results?search_query=cppcon some of them are mainly/only targetted at PC development, but a vast majority are applicable to embedded development.
- Jason turner youtube channel : https://www.youtube.com/channel/UCxHAlbZQNFU2LgEtiqd2Maw with C++ weekly, these are short technical videos on specific C++ aspects.

Let me know if you need more, or want to discuss specific aspects/features of C++ for embedded.

Thomas.
 
The following users thanked this post: sorin, samofab, Geoff_S, lucazader, genghisnico13, sundance

Offline Otatiaro

  • Regular Contributor
  • *
  • Posts: 85
Re: c vs cpp for stm32
« Reply #47 on: January 14, 2019, 12:32:23 pm »
Hello,

A well written C++ code can be more efficient than C or assembler one
You do realize that claim is completely preposterous, or a straight lie?  That is exactly the kind of argument that has negative value in a serious discussion.

I think you are overreacting because you know a bit better formulated he is perfectly right, let me improve just a bit the writting of what he meant:
"A medium written C++ code can be more efficient than medium written C or assembler one".
And that is exactly what I desmonstrated just above using the buffer fill problem, and it's perfectly true.

I'd even say that medium written C++ will most probably be faster that medium written C, and definitely be faster than medium written ASM. Plus it is easier to read, far less error-prone, far easier to write, re-usable (compared to ASM), and much more.

So yay on the performance aspect, for a specific task, that really need ultimate optimization, MAYBE C or assembler can be a bit faster than well written C++.
What percentage of developers are able to write correct, fully optimized ASM ?
How many of these happy few can optimize the program outside the boundary of one or a few functions (optimizing code over the entire program, depending on how it's called and the context) ?
And then, what time will it take for them to write this ASM code, compared to C++ ?
What happens if somebody else need to read and understand this code ?

Our in-house RTOS uses some ASM code, not for performance but to access platform specific resources that are not available in plain C++ (SVC and context change mainly). So ASM has it's usage, I'd just not place performance on top of my list.

Thomas.
 

Offline Otatiaro

  • Regular Contributor
  • *
  • Posts: 85
Re: c vs cpp for stm32
« Reply #48 on: January 14, 2019, 12:39:56 pm »
Nothing can be more efficient than assembly code, because is is just an exact representation of the machine code compilers generate.

And I prove you wrong :

int main()
{
    int a = 1,b = 1;
    return a+b;
}

Versus (probably not 100% correct, I'm writting it on the fly):

movs R0, #1
movs R1, #1
adds R0, R0, R1
BX LR

Why ? Check on godbolt.org, the C++ code (which is perfectly fine in C, by the way) outputs "movs r0, #2 | bx lr".
No optimized ASM code can do better (that I know of at least ...).

And I'm begin gentle with you, if you want to play with words I could have added a couple NOP in the ASM version ;)

Thomas.

[EDIT] I was about to tell you to actually watch the youtube video of Jason Turner about the commodore 64 experiments, but you clearly are to be classified in the first category I described. Nothing we can write, explain, prove to you will make you change your mind.
« Last Edit: January 14, 2019, 12:42:44 pm by Otatiaro »
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 1983
  • Country: ca
Re: c vs cpp for stm32
« Reply #49 on: January 14, 2019, 03:25:21 pm »
Is there a way to evaluate an micro based project needs OOP?

OOP is a programming concept. This is not equivalent to C++. You can do OOP in C as well, or in assembler if you wish.

The idea is very simple. An object contains data combined with functions. These functions are called methods. The user of the object doesn't know what's inside the object - the only thing exposed is how to find and call virtual methods. Thus, you can write a program which uses the object without knowing how the object works. This is a general idea.

Implementations may be vastly different. C++ is one. Objective-C is another. These two have very little in common. You can create your own if you wish to, according to your needs. Linux kernel uses OOP ideas in C.

Whether you need OOP or not depends on your design. There are cases where OOP can help a lot. You may even find that you're already using OOP ideas even though you don't call it OOP. There are cases where OOP can produce tremendous bloat.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf