C++ 如何解释其中带有“+”的 cout?
How does C++ interpret a cout with a '+' in it?
我一直在使用 Java/C++ 来回移动,所以我搞砸了我的控制台输出,不小心写了如下行:
cout << "num" + numSamples << endl;
cout << "max" + maxSampleValue << endl;
每一个都给了我程序中其他字符串的点点滴滴。我现在意识到我的错误,但是 C++ 是如何解释这些行的,以便它们在我的程序中输出不同字符串的不同部分?
"num"
类型是 char const [4]
。如果 numSamples
为整数,则 "num" + numSamples
类型为 const char *
。所以你调用 operator <<
cor std::cout
,为 const char *
重载并打印从地址 addres("num") + numSamples 开始的字符串在指针算术中。
试试这个:
cout << "num" + std::to_string(numSamples) << endl;
cout << "max" + std::to_string(maxSampleValue) << endl;
std::to_string()
函数可以在 <string>
中找到
这只是指针运算。例如,
cout << "num" + 1 << endl;
将打印从 ((address of)"num" + 1)
开始的字符串,即 "um"
.
如果我们添加的值超过字符串的长度,那么我们有未定义的行为。
原因很简单:
"num"
和 "max"
是字符串文字。他们的类型是const char *
。
假设 numSamples
是一个整数,你正在做的是指针运算。
你基本上是在打印一个指向 "num"
+ numSamples
字节的字符串。
如果你这样做 cout << "num" + 1 << endl
这将打印 "um"
.
你可能已经明白了,但正确的做法是:cout << "num" << numSamples << endl;
另外,你问:
But what was C++ interpreting those lines as so that they output
different parts of different strings in my program?
如前所述,"num"
是一个字符串文字。通常字符串文字位于二进制程序中的相同位置:.rodata
。所有其他字符串文字都位于该区域,因此当您将指针前进一定数量的字节时,您可能会指向其他一些字符串文字,从而打印(部分)它们。
请记住,尽管 iostream 重载 <<
(和 >>
)来执行 I/O,但这些最初被定义为位移运算符。当编译器解析表达式时,它基本上是在查看 "operand, operator, operand",然后检查操作数是否属于可以应用该运算符的类型。
在这种情况下,我们有一个字符串文字和(显然)某种整数,并且编译器知道如何对它们进行数学运算(在将字符串文字转换为指针之后)。
然而,从编译器的角度来看,这与以下内容并没有太大区别:
int a, b=1, c=2, d = 3;
a = b << c + d;
区别在于int
类型的操作数,意思很明显:它在做加法和位移。在 iostream 中,<<
和 >>
的含义发生了变化,但它们在表达式中的语法不变。
从编译器的 "viewpoint" 来看,唯一的问题是 +
的操作数是否属于允许 +
的类型——在这种情况下,您有 pointer to char + integer
,所以这是允许的。结果是一个指向 char 的指针,它有一个 <<
的重载,它接受一个类型为 ostream 的左手操作数和一个类型为 pointer to char
的右手运算符,所以整个表达式是很好(就它而言)。
如果您查看 operator_precedence,您会看到 +
在 <<
之前被求值,这使得该表达式在传递给运算符 [=12= 之前需要求值]:
"num" + numSamples
现在 "num"
将成为 static const char *
,我假设 numSamples
是整数类型。由于 +
的左侧是指针类型并且您要向其添加,这就是指针算术。 cout 现在获得一个指向内存中比 "num"
或 "max"
多 numSamples
或 maxSamplueValue
的位置的指针。您的所有静态字符串很可能都在同一内存区域中排列,这就是您看到它们而不是随机乱码的原因。
我一直在使用 Java/C++ 来回移动,所以我搞砸了我的控制台输出,不小心写了如下行:
cout << "num" + numSamples << endl;
cout << "max" + maxSampleValue << endl;
每一个都给了我程序中其他字符串的点点滴滴。我现在意识到我的错误,但是 C++ 是如何解释这些行的,以便它们在我的程序中输出不同字符串的不同部分?
"num"
类型是 char const [4]
。如果 numSamples
为整数,则 "num" + numSamples
类型为 const char *
。所以你调用 operator <<
cor std::cout
,为 const char *
重载并打印从地址 addres("num") + numSamples 开始的字符串在指针算术中。
试试这个:
cout << "num" + std::to_string(numSamples) << endl;
cout << "max" + std::to_string(maxSampleValue) << endl;
std::to_string()
函数可以在 <string>
这只是指针运算。例如,
cout << "num" + 1 << endl;
将打印从 ((address of)"num" + 1)
开始的字符串,即 "um"
.
如果我们添加的值超过字符串的长度,那么我们有未定义的行为。
原因很简单:
"num"
和 "max"
是字符串文字。他们的类型是const char *
。
假设 numSamples
是一个整数,你正在做的是指针运算。
你基本上是在打印一个指向 "num"
+ numSamples
字节的字符串。
如果你这样做 cout << "num" + 1 << endl
这将打印 "um"
.
你可能已经明白了,但正确的做法是:cout << "num" << numSamples << endl;
另外,你问:
But what was C++ interpreting those lines as so that they output different parts of different strings in my program?
如前所述,"num"
是一个字符串文字。通常字符串文字位于二进制程序中的相同位置:.rodata
。所有其他字符串文字都位于该区域,因此当您将指针前进一定数量的字节时,您可能会指向其他一些字符串文字,从而打印(部分)它们。
请记住,尽管 iostream 重载 <<
(和 >>
)来执行 I/O,但这些最初被定义为位移运算符。当编译器解析表达式时,它基本上是在查看 "operand, operator, operand",然后检查操作数是否属于可以应用该运算符的类型。
在这种情况下,我们有一个字符串文字和(显然)某种整数,并且编译器知道如何对它们进行数学运算(在将字符串文字转换为指针之后)。
然而,从编译器的角度来看,这与以下内容并没有太大区别:
int a, b=1, c=2, d = 3;
a = b << c + d;
区别在于int
类型的操作数,意思很明显:它在做加法和位移。在 iostream 中,<<
和 >>
的含义发生了变化,但它们在表达式中的语法不变。
从编译器的 "viewpoint" 来看,唯一的问题是 +
的操作数是否属于允许 +
的类型——在这种情况下,您有 pointer to char + integer
,所以这是允许的。结果是一个指向 char 的指针,它有一个 <<
的重载,它接受一个类型为 ostream 的左手操作数和一个类型为 pointer to char
的右手运算符,所以整个表达式是很好(就它而言)。
如果您查看 operator_precedence,您会看到 +
在 <<
之前被求值,这使得该表达式在传递给运算符 [=12= 之前需要求值]:
"num" + numSamples
现在 "num"
将成为 static const char *
,我假设 numSamples
是整数类型。由于 +
的左侧是指针类型并且您要向其添加,这就是指针算术。 cout 现在获得一个指向内存中比 "num"
或 "max"
多 numSamples
或 maxSamplueValue
的位置的指针。您的所有静态字符串很可能都在同一内存区域中排列,这就是您看到它们而不是随机乱码的原因。