This compiler business is not my forte...
I want to use the <string> template library in my embedded c code.
For example (sudo code):
#include <string>
int main() {
std::string str = std::to_string(3.87628);
}
When I try to compile this code, I get the error:
error: 'to_string' is not a member of 'std'
My Makefile contains the following flags:
# compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
# Generate dependency information
CFLAGS = -MMD -MP -MF"$(@:%.o=%.d)"
# C Flags
CPPFLAGS = $(CFLAGS)
CPPFLAGS = \
-fno-exceptions \
-fno-rtti
C_STANDARD = -std=gnu11
CPP_STANDARD = -std=gnu 14
To my understanding, the inclusion of flag -std=gnu 14 should have me covered no?
CodePudding user response:
std::to_string is part of the library, not the language. So -std=gnu 14 will have no effect if it is not implemented in the library. Check the header file to see if
- it is declared, and
- if it is dependent on any macros being defined.
The code you presented is also nonsense. It should be:
std::string str = std::to_string(3.87628);
but that won't solve your problem.
The library is separate from the compiler, and your toolchain may be using an older C library or a cut-down library aimed at embedded systems. From where did your source the toolchain and what C library is it using? The copyright message in the header may provide a clue - including version information.
The std::string library is often inappropriate in embedded systems because amongst other issues it relies on non-deterministic dynamic memory allocation.
Since your code suggests you are actually using C strings rather than std::string you might consider:
#include <cstdio>
int main()
{
char str[32] ;
std::snprintf( str, sizeof(str), "%f", 3.87628 ) ;
}
CodePudding user response:
The presence of C in embedded systems is problematic. Lets run your code on an g ARM32 10.2.1 gcc none-eabi compiler with maximum optimizations -O3 -std=c 17 enabled:
.LC0:
.ascii "%f\000"
main:
str lr, [sp, #-4]!
adr r1, .L15
ldmia r1, {r0-r1}
sub sp, sp, #36
stm sp, {r0-r1}
ldr r3, .L15 8
add r0, sp, #8
mov r2, #328
ldr r1, .L15 12
bl std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > __gnu_cxx::__to_xstring<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, char>(int (*)(char*, unsigned int, char const*, std::__va_list), unsigned int, char const*, ...)
ldr r0, [sp, #8]
add r3, sp, #16
cmp r0, r3
ldrne r1, [sp, #16]
addne r1, r1, #1
blne _ZdlPvj
mov r0, #0
add sp, sp, #36
ldr lr, [sp], #4
bx lr
.L15:
.word 380705901
.word 1074725535
.word .LC0
.word vsnprintf
Now wth is all this bloat!? Did I forget the -O3 flag, huh, no I didn't... The program you posted has no side effects. Or so we thought - we've been cplusplus:ed. I would have expected a correctly behaving compiler to generate no code under -O3.
So the question is clearly not how to use std::string in the project and the answer isn't "In C 2x you didn't use constexpr this is not how you write modern C blahblah". The question is rather how to salvage the project once some PC programmer did drag this completely unacceptable code into your microcontroller just because someone decided to allow C . The answer to that follows:
Step 1: switch to C. Same compiler ARM32 10.2.1 gcc none-eabi.
Step 2: don't waste time on bloat classes when there is no need for them. A simple thing such as converting a float constant to a string can and should be done in the pre-processor. Any intermediate-level C or C programmer ought to know about stringification macros:
#define S(x) #x #define STR(x) S(x)Step 3: test. A simple test program with
-ffreestandingand some side-effect to ensure that the string doesn't get optimized out, for example:#include <stdio.h> #define S(x) #x #define STR(x) S(x) void main (void) { char str[] = STR(3.87628); puts(str); // just to introduce a side effect }
The relevant parts of the resulting machine code is now something like this:
.LC0:
.ascii "3.87628\000"
main:
str lr, [sp, #-4]!
sub sp, sp, #12
mov r3, sp
ldr r2, .L4
ldm r2, {r0, r1}
stm r3, {r0, r1}
.L4:
.word .LC0
This code is fine. We can get on with writing our application.
