18

I am new to C++17 and to std::string_view. I learned that they are not null terminated and must be handled with care.

Is this the right way to printf() one?

#include<string_view>
#include<cstdio>

int main()
{
    std::string_view sv{"Hallo!"};
    printf("=%*s=\n", static_cast<int>(sv.length()), sv.data());
    return 0;
}

(or use it with any other printf-style function?)

11
  • 9
    Why you want to use printf in c++ at all? Commented Jun 10, 2022 at 14:00
  • 6
    I learned that they are not null terminated That's not entirely correct. A string_view can be non-null terminated, but only if you create it as such. "Hallo" has a null terminator, so sv will as well. Commented Jun 10, 2022 at 14:01
  • 3
    Is this what you are asking? Using printf with a non-null terminated string Commented Jun 10, 2022 at 14:03
  • I believe it should be "=%.*s=\n"... Just checked, that's correct. Commented Jun 10, 2022 at 14:05
  • 4
    Consider use fmt library it should easy to transform code which uses printf. Commented Jun 10, 2022 at 14:30

4 Answers 4

22

This is strange requirement, but it is possible:

std::string_view s{"Hallo this is longer then needed!"};
auto sub = s.substr(0, 5);
printf("=%.*s=\n", static_cast<int>(sub.length()), sub.data());

https://godbolt.org/z/nbeMWo1G1

As you can see you were close to solution.

Sign up to request clarification or add additional context in comments.

8 Comments

casting to an int can lead to UB. Does printf support passing a size_t for the length of the string?
@NathanOliver No, only int is supported.
@kuga No, it's not wrong. The * is what receives the precision. So, '.5s', sv.data() or '.*s', (int)sv.size(), sv.data() does the same thing (as long as size() doesn't overflow the int).
printf requires int value there so cast is needed. Star parameter doesn't have any modifiers to change expected type. It is possible to implement safe casting to int, but IMO it would be overkill.
I was more thinking to implement template which could be called clip_cast.
|
10

You can use:

assert(sv.length() <= INT_MAX);
std::printf(
    "%.*s",
    static_cast<int>(sv.length()),
    sv.data());

Comments

0

If using google's Abseil library (https://abseil.io/) the absl::PrintF function can safely print a string view (either std::string_view or absl::string_view).

From the Abseil documentation of absl::PrintF at https://github.com/abseil/abseil-cpp/blob/master/absl/strings/str_format.h

std::string_view s = "Ulaanbaatar";
absl::PrintF("The capital of Mongolia is %s", s);

Comments

-6

The thing to remember about string_view is that it will never modify the underlying character array. So, if you pass a C-string to the string_view constructor, the sv.data() method will always return the same C-string.

So, this specific case will always work:

#include <string_view>
#include <cstdio>

int main() {
    std::string_view sv {"Hallo!"};
    printf("%s\n", sv.data());
}

4 Comments

I'd warn against doing this in the general case, since not all views are null-terminated.
@holyBlackCat – i was very specific that it's only for C-string constructed string_view objects.
not sure why this is "-2" since in the above requested case the string_view is null-term. see ctor #4 in string_view in cppref. Yes, it's a view that is not null term, but I'd change the original question to be more general.
Access to basic_string_view::operator[](size()) (the nul terminator in this case) has undefined behaviour. You can use this trick because it works, but you should feel dirty every time, I do :-(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.