operator const char* return

Pages: 12
Before the stdlib formatting library in C++20 there was the <iomanip> library.

https://en.cppreference.com/w/cpp/header/iomanip

std::format AFAIK is based on the {fmt} library.

https://fmt.dev/latest/index.html

The formatting specification for this library is based on Python, as seeplus mentioned.

The format string syntax is extensive, as you've discovered. The format string for C's printf is just as extensive and complicated.

https://fmt.dev/latest/syntax.html

C++20 didn't roll over the entire fmt library, a couple of features were added into C++23. std::print and range-based formatting. C++23 added something new, std::println.

For me using the <iomanip> library is so busted now, C++ now provides compact I/O manipulation.

As I mentioned in another topic:

I would recommend two books, one on C++20 and the other on C++23, by the same authors. The books have github repos, one I got the range formatting workaround from.

Beginning C++20: From Novice to Professional
https://link.springer.com/book/10.1007/978-1-4842-5884-2

Beginning C++23: From Beginner to Pro
https://link.springer.com/book/10.1007/978-1-4842-9343-0

Yes, they are eBooks, I have the C++20 book in a dead tree edition. And find it very flimsy and hard to read compared to the eBook.

I own both books and really recommend getting both. Each book cover much of the same material with examples and exercises of the other. The C++20 book has many of the examples/exercises that use modules in non-module form.
Have you all ...

With
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS False)

in recent projects and
$ g++ --version
g++ (GCC) 11.4.1 20230605 (Red Hat 11.4.1-2)

such familiarity would be rather academic.
C++20 text formatting was made available with GCC 13, the formatting <print> library with GCC 14.

I don't notice such things since I use Visual Studio.

@keskiverto, you could use the {fmt} library with your set up.
I didn’t mean to come off as harsh or upset you.

I think seeplus had more tact than I did in expressing what I was really trying to say:
I strongly suggest that you get in the habit of always writing 'correct' code - even for test or learning purposes.


It is the ease with which you can write corner code that will break that made people from the US gov recently trash use of C and C++.

Sorry friend. Don’t let setbacks or worries stop you. You’ve been asking good questions and doing great, so... Just keep learning and programming!
I have never experienced either of the two above not working but since it is being told to me by the collective experience i believe it. i would be more appreciative if i saw it firsthand even so. is there a known formula for a cout, maybe through some overexaggerated algorithm that will show the const char* expiration before the cout usage?


Sure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <string>
#include <iostream>
#include <format>

struct MyAddress 
{
    std::string Address_1, Address_2, City, State, PostalCode; 
    
    std::string FullAddress; 
	operator const char* ()
	{
		FullAddress = std::format("{}\n{}\n{} {} {}", Address_1, Address_2, City, State, PostalCode);
		return FullAddress.c_str();
	}
};

void process_order(char const* mailing_address, char const* billing_address)
{
  std::cout << "Mailing address: " << mailing_address << "\n"; 
  std::cout << "Billing address: " << billing_address << "\n";
}

int main()
{
    MyAddress address{ "1 First St", "Example Town", "My City", "Anywhere", "10000" };
    // use the above  as both a mailing and billing address
    process_order(address, address); 
}


With LLVM Address Sanitizer, a possible output is:

=================================================================
==24377==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000010 at pc 0x7f186529e7f1 bp 0x7ffcc07c86e0 sp 0x7ffcc07c7ea0
READ of size 2 at 0x604000000010 thread T0
    #0 0x7f186529e7f0  (/usr/local/lib64/libasan.so.8+0x637f0)
    #1 0x402a15 in process_order(char const*, char const*) (/tmp/1711383839.624552/a.out+0x402a15)
    #2 0x4027bf in main (/tmp/1711383839.624552/a.out+0x4027bf)
    #3 0x7f18642f782f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) (BuildId: b5381a457906d279073822a5ceb24c4bfef94ddb)
    #4 0x4028e8 in _start (/tmp/1711383839.624552/a.out+0x4028e8)

0x604000000010 is located 0 bytes inside of 47-byte region [0x604000000010,0x60400000003f)
freed by thread T0 here:
    #0 0x7f1865310b18 in operator delete(void*, unsigned long) (/usr/local/lib64/libasan.so.8+0xd5b18)
    #1 0x40a71a in MyAddress::operator char const*() (/tmp/1711383839.624552/a.out+0x40a71a)

previously allocated by thread T0 here:
    #0 0x7f186530fc18 in operator new(unsigned long) (/usr/local/lib64/libasan.so.8+0xd4c18)
    #1 0x4085ee in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (/tmp/1711383839.624552/a.out+0x4085ee)

SUMMARY: AddressSanitizer: heap-use-after-free (/usr/local/lib64/libasan.so.8+0x637f0) 
Shadow bytes around the buggy address:
  0x603ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x603ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x603ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x603fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x603fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x604000000000: fa fa[fd]fd fd fd fd fd fa fa 00 00 00 00 00 07
  0x604000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x604000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x604000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x604000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x604000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==24377==ABORTING
Last edited on
Have you all become familiar with std::format and have you warmed up to it


I originally learnt formatting with c printf() way, way back in the mists of time which can look as bad (or worse) than that used by std::format(). Moving from the syntax used with printf() to that used with std::format() is easy. :)
std::cout << std::format("Combined: {:*<+14.4f}, {:+#09x}\n", pi, 314);


As used, consider:

1
2
3
4
5
6
7
#include <iostream>
#include <format>
#include <numbers>

int main() {
	std::cout << std::format("Combined: {:*<+14.4f}, {:+#09x}\n", std::numbers::pi, 314);
}


Which displays:


Combined: +3.1416*******, +0x00013a


Lets take it apart. There are two sets of {}, so there are two format specs. The first is {:*<+14.4f}.

: means use the next argument. You can also specify an argument number following :
* is the pad char to be displayed if the total number of chars is less than that specified.
< left align the output
+ means display a sign for both positive and negative numbers
14.4 is the minimum field width (14) and precision (4). The output starting with the initial + and finishing with the final * is 14 chars. There are 4 digits to the right of the .
f means that the argument is a floating-point number and should be converted using the std::chars_format::fixed_precision option for std::to_chars()

The second is {:+#09x}

: use the next argument
+ display a sign for both positive and negative numbers
# means use the alternative output form. For integers if applicable first output either 0b, 0 or 0x for binary, octal or hex respectively
0 pad the output with 0's
9 specifies the minimum field width
x specifies to output as hex using lowercase letters

Easy peasy!

Thank you George P, i will do formatting on occasions but even that i am limited in. I have used iomanip but not the c printf. i do understand Duthomhas's printf.

I am glad that std::format follows Python and that will be one less thing to learn if i ever dive into it.

Duthomhas, all is understood and i appreciate your concern in making me a programmer yet, one day. I am hoping you and others will rub off on me gradually. This group is an inspiration and if you had the platform i am sure you can convince the gov..

mbozzi, thank you. I see the error/issue. Is that what programmers do, pass class/struct objects into char pointers? Is that common and needed? i have not done that and I don't think I need to at this juncture. I have seen them passed as char* to binary files. If that is the case then i see the problem.

seeplus, thank you for the explanation. I have to commit it to memory at some point and test after not seeing it for some time. I code sporadically but not for a job and I might not see things for months again. That is why i was practicing my overloaded ops since i have not done them for a while now.
What and how I pass into/out of functions depends on design considerations. Passing pointers into a function, depends. Out of a function, never.

In/out parameters can be achieved using references.

C++ offers much better memory management than using raw pointers, less likely to have memory leaks.

seeplus wrote:
Moving from the syntax used with printf() to that used with std::format() is easy. :)

Testify!! Preach that Gospel! :Þ
I have to commit it to memory at some point


Just have a browser bookmark to the relevant cppreference page and keep it as an open browser tab. I permanently keep open a web browser with about half dozen tab pages for fast access when needed. Don't sweat the small stuff, know where to find it. Concentrate on the bigger issues and what's available in the language. eg I don't remember all the available std::algorithm but that is one of my browser tabs ( https://en.cppreference.com/w/cpp/algorithm ).
Where have you first been exposed to this problem? Is this something that is in a C++ introductory book and in what section? Is this something in a more advanced book?


I first learnt c way back in the 1980's before C++ was generally available. For c you have to learn memory management as you can't do much without it. You soon learnt the error of your ways!

For C++ I started with an early version of Horton's C++ book and then the excellent (but now very dated) Sutter (Exceptional C++ series) and Meyers (Effective C++ series) sets of books.
Hi

Some other things to be aware of, mainly how the history of C++ has effected the way it has been taught:

Back in the day, say 25 years ago, there were quite a few authors who had learnt C first, then when it came to writing C++ books, they included a lot of C style code. Or the book consisted of a whirlwind tour C, followed by a short introduction to C++. There is still some of that around. One of the biggest red flags for me is seeing a mixture of C and C++. Even pedantic things like int main(void) is evidence to me that the coder has a C background. If one is curious about that, the use of void as a parameter has never been a requirement for C++. Oh, if you see void main(void) get out the fire extinguisher right away!!

Also C++ is an evolving language (there is a new standard every 3 years), consequently the way it has been taught has changed. For example, at one stage the use of new and delete was promoted a lot, but now we have better tools like smart pointers, and RAII is been promoted more. RAII is Resource Acquisition Is Initialization, and it basically means acquire the resource in the constructor and release it in the destructor. So your question about printing things is a great example of the way things have changed.

So the last 2 paragraphs are about avoiding out of date advice / documentation.

I would also recommend sites such as learncpp, the C++ Core Guidelines as others have mentioned.
seeplus wrote:
the excellent (but now very dated) Sutter (Exceptional C++ series) and Meyers (Effective C++ series) sets of books.

Lovely books. Yes, the newer standards replace some of the issues that those books did show how to cope with, but IMHO, they are more on the "why" than "how", and that makes reader think (rather than just copy-paste the using namespace hell;). One can think about the features of the new standards, just like one could of the old features.

Sutter started to renew some of the GotW https://herbsutter.com/gotw/ but C++ is now much more on the move than before 2011.
Teach beginners modern C++ practices, C++ 101. std::string, std::vector, random library, etc. C++ is rapidly evolving, modules are a prime example.

Intermediate/Advanced C++ then should circle back and expose students to older ways of coding, including C. Programmers will deal with legacy code eventually. Even us self-taught hobbyist types.

There is still some functionality in C that hasn't been added to the C++ stdlib -- please don't ask what parts, I don't remember off the top of my head without research -- though that gap is disappearing.

Books (yes, books. more than one‡) are a needed learning and reference resource. Along with online resources such as the Learn C++, the C++ Core Guidelines and cppreference websites. Online resources are quicker to be updated. Books, even the majority of eBooks are set in stone and outdated from the moment they are published.

https://isocpp.org/wiki/faq/how-to-learn-cpp#buy-several-books

Trying to use bleeding edge C++ can be difficult at times, not all compilers are 100% compliant with later standards. C++20 still has a handful of gaps except for MSVC, no compiler is fully up-to-date with C++23.

And don't even think about C++26. Not yet formally adopted, though some of the proposed features are available.
Oh, and learn to be flexible when coding using C++, especially with newer standard C++.

When C++20 was first adopted if the std::format format string was malformed that could only be detected at run-time. So the C++20 books I own (and many online examples) used try/catch blocks to detect bad formatting.

Now a malformed format string is compile-time detectable! That makes it much easier to correct things. It also made the book examples out-dated.

A recommendation, use more than one compiler to mash code, as long as the code written is standard compliant and compilable. My primary compiler is the Visual Studio IDE, my secondary is Code::Blocks with GCC custom updated to the latest version.

I've been thinking about learning to code via command-line instead of an IDE. MSYS2 is one such possibility.

Always examine warnings, consider setting compiler flags to treat warnings as errors and halt compilation. Up the warning level as well.

Bottom line, what works with one compiler isn't guaranteed to work with another. Returning a raw char pointer (C string) might be detected as a problem. Either as a warning or an error.
I use MSVC and LLVM/Clang as my primary toolsets, and I avoid going into the VS IDE as much as possible. I do nearly everything at the command line.

1
2
3
4
5
6
7
8
9
#include <iostream>

int main( int argc, char ** argv )
{
    const char * name = "world";
    if (argc > 1) name = argv[1];

    std::cout << "Hello " << name << "!\n";
}

  • cl /EHsc /W4 /Ox /std:c++17 /utf-8 hello.cpp
  • clang++ -Wall -Wextra -Werror -pedantic-errors -O3 -std=c++17 hello.cpp

I also keep MSYS2 and MinGW-w64 and TDM around, as well as Clang and GCC on WSL.

(And, now that I’ve switched to Linux on my new PC, I now have to figure out how to frob MSVC properly or, alternately, cross-compile. Fooey.)

But yes, testing with at minimum MSVC and Clang and GCC is a Good Thing. Doing so often fixes problems in my code I would not have caught otherwise.
Last edited on
I know I shouldn't rely on the VS IDE, but I guess I'm too lazy to spend any time learning how to do compiling from the command-line. ::shrug::
It’s really easy.

The two [code] things I gave above are about it, actually.

There are a few things to worry about:

    • Compiler-specific stuff on Windows. For MSVC, that’s /EHsc, which just means “do exception handling the normal way”, and /utf-8 on MSVC 17 and earlier, meaning “program source files are UTF-8”.

    • Warning levels. I usually crank them up to maximum. That’s /W4 for MSVC and -Wall -Wextra -Werror -pedantic-errors on GCC and Clang. If I want to be a little more lax while debugging, I’ll drop to /W3 or leave off the -Werror.

    • Optimization levels. MSVC does Release mode optimization by default. You’ve got to tell Clang and GCC with -O3.

    • The C++ Standard you wish to compile against. That option should be obvious. For MSVC, you can also specify -std=c++latest to get the best of whatever the folks at MS have managed to implement so far.

    • If you want GCC or Clang to produce “hello.exe” instead of “a.exe” (or “a.out”), you need to tell it with the -o hello option. That’s /Fe:hello.exe with MSVC, but you don’t usually have to specify that.

You can also supply include directories with individual -Idirname otpions, and a myriad of other things, but that usually suffices.

Oh, and compile to object file with -c.

That’s it!
There is also cmake (or other build tools), which could be done from the cmd line, but I guess it's like learning another language. One could see what files are produced in VS, and go from there. VSCode at least, automatically puts some of the settings from the IDE into files used by cmake.

Some of the warning options not enabled by -Wall -Wextra or -pedantic :

-Wswitch-default -Wswitch-enum
-Wfloat-equal
-Wshadow
-Wconversion -Wsign-conversion
-Weffc++
-Wlogical-op
If I were to start using command-line compilation I would probably go with CMake at first.

I've diddled around with MSYS2, but it was rather intimidating at the time.

Enabling all the warning options really makes compiling WinAPI apps go nutso. No thanks for that option.

For console apps, yes. Enable as much as possible.
Topic archived. No new replies allowed.
Pages: 12