正确的方式打印 std::string_view 是什么?

15

我刚接触C++17和std::string_view,了解到它们不是以空字符结尾的字符串类型,必须小心处理。

这样printf()一个字符串是否正确?

#include<string_view>
#include<cstdio>

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

(或者将其与任何其他printf风格的函数一起使用?)


8
为什么你在C ++中想要使用printf - Marek R
5
我得知它们不是以空字符结尾的。这并非完全正确。如果您明确地创建了一个string_view,则它可以是非空字符结尾的。因为 "Hallo" 是以空字符结尾的,所以 sv 也是。 - NathanOliver
3
这是你在问的吗?使用printf打印非空结尾字符串 - Drew Dormann
@MarekR 我修改了现有的代码,其中过度使用printf()。我想保持风格并尽量不改变太多。我上面的代码显然只是一个简短的示例。 - kuga
4
考虑使用 fmt 库,它可以很容易地将使用 printf 的代码转换。 - Marek R
显示剩余6条评论
3个回答

16
这是一个奇怪的要求,但是可以实现。
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

你看,你离解决办法很近了。

@NathanOliver 不支持其他类型,只支持 int - Ted Lyngmo
1
@kuga 不,这没错。* 是接收精度的符号。因此,'.5s',sv.data()'.*s',(int)sv.size(),sv.data() 做的事情是一样的(只要 size() 没有超出 int 的范围)。 - Ted Lyngmo
1
printf 需要一个 int 值,因此需要进行转换。Star 参数没有任何修饰符来改变预期类型。可以实现安全转换为 int,但我认为这将是过度的。 - Marek R
过度杀伤版 :-) - Ted Lyngmo
1
我更倾向于实现一个名为 clip_cast 的模板。 - Marek R
显示剩余4条评论

10

您可以使用以下方法:

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

-2
关于 string_view 的要点是它永远不会修改底层的字符数组。因此,如果您将 C 字符串传递给 string_view 构造函数,则 sv.data() 方法将始终返回相同的 C 字符串。

因此,这种特定情况将始终有效:

#include <string_view>
#include <cstdio>

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

6
一般情况下,我建议不要这样做,因为并非所有视图都以null结尾。 - HolyBlackCat
1
@holyBlackCat - 我特别指出只适用于使用C字符串构造的 string_view 对象。 - Bill Weinman
不确定为什么这是“-2”,因为在上面的请求案例中,string_view是null-term的。请参见cppref中string_view的ctor#4。是的,它是一个非空终止符的视图,但我会更改原始问题以使其更一般化。 - Kobi
访问basic_string_view :: operator [](size())(在这种情况下是nul终止符)具有未定义的行为。您可以使用此技巧,因为它有效,但每次都应该感到不舒服,我也是如此 :-( - Sandy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接