为什么在c++中没有编译器警告的std :: string notection行为?

发布于 2025-01-27 02:13:56 字数 702 浏览 2 评论 0原文

在我的代码中,我使用记录语句为了更好地查看发生了什么。有时我按以下内容编写代码:

int i = 1337;
// More stuff...
logger->info("i has the following value: " + i);

在调试模式下编译和执行时,这不会按预期打印出i(例如,这是在Java/c#中工作的方式),它会打印出乱七八糟的东西。但是,在发布模式下,这也可能会使整个应用程序崩溃。 c ++标准对将int附加到std :: String的标准说什么?

当我编译代码调用明显的未定义行为时,为什么编译器根本不警告我?我想念什么吗?我正在使用Visual Studio 2022(MSVC)。执行记录语句的正确方法是将int转换为std :: string显式:

logger->info("i has the following value: " + std::to_string(i));

但是,此错误在开发过程中很容易通过。我的警告级别设置为Level4(/W4)

In my code I use logging statements in order to better see what's going on. Sometimes I write code like the following:

int i = 1337;
// More stuff...
logger->info("i has the following value: " + i);

When compiled and executed in debug mode this does not print out i as expected (this is how it would work in Java/C# for example), it rather prints something garbled. In release mode however this might as well crash the entire application. What does the C++ standard say about appending ints to a std::string like I'm doing here?

Why does the compiler not warn me at all when I compile code invoking obvious undefined behavior like this? Am I missing something? I'm using Visual Studio 2022 (MSVC). The correct way to do the logging statement would be converting the int to a std::string explicitly:

logger->info("i has the following value: " + std::to_string(i));

However this bug easily slips through during development. My warning level is set to Level4 (/W4).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初熏 2025-02-03 02:13:56

问题在于,

logger->info("i has the following value: " + i);

您不使用std :: String。您将int添加到字符串文字中,即const char [] array。 const char []在某些情况下衰减到const char*指针。在这种情况下,int将指针以1337个字符向前前进,这超出了字符串字面的末尾,因此不确定的行为。

您应该得到一个更好的编译器,以警告您,即:

foo.cc:7:42: warning: offset ‘1337’ outside bounds of constant string [-Warray-bounds]
    7 |     foo("i has the following value: " + i);
      |                                          ^

您可以使用std :: string像这样的文字:

#include <string>
using namespace std::literals;

void foo(std::string);

void bla() {
    int i = 1337;
    foo("i has the following value: "s + i);
}

然后您会遇到一个“ net net new”错误,即“ std :: string + int + int “在C ++中不是一件事情:

foo.cc:8:40: error: no match for ‘operator+’ (operand types are ‘std::__cxx11::basic_string<char>’ and ‘int’)
    8 |     foo("i has the following value: "s + i);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~
      |         |                                |
      |         std::__cxx11::basic_string<char> int
...
going on for 147 lines

之后,应该很明显,您想要的是:

logger->info("i has the following value: "s + std::to_string(i));

使用std :: String文字避免这样的错误,因为它会发出警告(您的编译器)甚至都不会给您的错误错误,迫使您编写正确的代码。因此,我建议使用s后缀所有字符串。

The problem is that in

logger->info("i has the following value: " + i);

you are not working with std::string. You are adding an int to a string literal, ie a const char[] array. The const char[] decays into a const char* pointer in certain contexts. In this case, the int advances that pointer forward by 1337 characters, which is way beyond the end of the string literal, and therefore undefined behavior.

You should get a better compiler that warns you about this, ie:

foo.cc:7:42: warning: offset ‘1337’ outside bounds of constant string [-Warray-bounds]
    7 |     foo("i has the following value: " + i);
      |                                          ^

You can use a std::string literal like this:

#include <string>
using namespace std::literals;

void foo(std::string);

void bla() {
    int i = 1337;
    foo("i has the following value: "s + i);
}

and then you get a "nicer" error that "std::string + int" isn't a thing in C++:

foo.cc:8:40: error: no match for ‘operator+’ (operand types are ‘std::__cxx11::basic_string<char>’ and ‘int’)
    8 |     foo("i has the following value: "s + i);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~
      |         |                                |
      |         std::__cxx11::basic_string<char> int
...
going on for 147 lines

After this, it should be obvious that what you want is this instead:

logger->info("i has the following value: "s + std::to_string(i));

Using std::string literals avoids mistakes like this, because it turns warnings (which your compiler doesn't even give) into hard errors, forcing you to write correct code. So I recommend using the s suffix for all strings.

不羁少年 2025-02-03 02:13:56

这条线是正确的,

logger->info("i has the following value: " + i);

在表达式中

"i has the following value: " + i

,使用指针算术。

例如,如果您要编写

logger->info("i has the following value: " + 6);

,则该行具有相同的效果,如果要编写

logger->info("the following value: ");

此行

logger->info("i has the following value: " + i);

等于行

logger->info( &"i has the following value: "[i]);

C ++标准在将INT附加到STD :: String的说法是什么
就像我在这里做

在表达式中在这里做的一样,没有类型std :: String的对象。有一个字符串字面的字符串,它只有一个普通数组类型,该数组类型是带有指针算术的表达式操作数。在表达式中,字符串文字被隐式转换为指针转换为其类型const char *的第一个元素。

This line is correct,

logger->info("i has the following value: " + i);

in the expression

"i has the following value: " + i

there is used the pointer arithmetic.

For example if you will write

logger->info("i has the following value: " + 6);

then this line has the same effect if to write

logger->info("the following value: ");

That is this line

logger->info("i has the following value: " + i);

is equivalent to the line

logger->info( &"i has the following value: "[i]);

What does the C++ standard say about appending ints to a std::string
like I'm doing here

In the expression there is no object of the type std::string. There is used a string literal that has just an ordinary array type that is an operand of an expression with the pointer arithmetic. In the expression the string literal is implicitly converted to a pointer to its first element of the type const char *.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文