[英]C++ program compiled in windows produces different output
I was solving a problem that involved incrementing a counter and displaying it. 我正在解决一个涉及增加计数器并显示它的问题。 The way I initialized and incremented the variable seemed pretty normal.
我初始化和递增变量的方式似乎很正常。 See counter variable
请参阅计数器变量
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[5];
int counter = 1;
while (cin >> s && (strcmp(s, "*") != 0))
{
cout << "Case " << counter++ << ": Hajj-e-A";
if (s[0] == 'H')
{
cout << "kbar\n";
}
else if (s[0] == 'U')
{
cout << "sghar\n";
}
}
}
but the program mysteriously displayed an incorrect result. 但是该程序神秘地显示了错误的结果。 It didn't increment the value, which started at 1, properly.
它没有适当增加从1开始的值。 See the output.
查看输出。
Case 1: Hajj-e-Akbar
Case 0: Hajj-e-Asghar
Case 1: Hajj-e-Akbar
Case 0: Hajj-e-Asghar
But when I tried compiling and running it through http://www.tutorialspoint.com/compile_cpp_online.php , which uses Linux, it produced correct results. 但是,当我尝试通过使用Linux的http://www.tutorialspoint.com/compile_cpp_online.php进行编译和运行时,它产生了正确的结果。 The program was also accepted by the online judge.
该程序也被在线法官接受。
Case 1: Hajj-e-Akbar
Case 2: Hajj-e-Asghar
Case 3: Hajj-e-Akbar
Case 4: Hajj-e-Asghar
Anyone can point out the mystery behind this? 任何人都可以指出其背后的奥秘吗? Why is the Windows-compiled code producing weird results?
为什么Windows编译的代码会产生奇怪的结果? Many thanks!
非常感谢!
This is a buffer overflow. 这是缓冲区溢出。 Most likely, when you compile on Windows, the
counter
variable immediately follows the s[5]
variable in memory, like this: 最有可能的是,当您在Windows上进行编译时,
counter
变量将紧随内存中的s[5]
变量,如下所示:
+----+----+----+----+----+----+----+----+----+
| ?? | ?? | ?? | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
\________ s[5] ________/ \____ counter ____/
Since Windows is little-endian, it's stored as 01 00 00 00
instead of 00 00 00 01
like you might expect. 由于Windows是低位优先的,因此它存储为
01 00 00 00
而不是您期望的00 00 00 01
。 The ??
??
just indicates that we don't know yet what's there - it could be anything. 只是表明我们尚不知道那里是什么-可能是任何东西。
Now, let's say you enter "Hardy" and press Enter. 现在,假设您输入“ Hardy”,然后按Enter。 In ASCII, that translates to the byte sequence
48 61 72 64 79 0D 0A
(the last two are the line ending, on UNIX the 0D
would be omitted). 在ASCII中,它转换为字节序列
48 61 72 64 79 0D 0A
(最后两个是行尾,在UNIX上, 0D
将被省略)。 This is what cin >> s
will do to the memory: 这是
cin >> s
对内存的作用:
1. Read in 'H':
+----+----+----+----+----+----+----+----+----+
| 48 | ?? | ?? | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
2. Read in 'a':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | ?? | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
3. Read in 'r':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | ?? | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
4. Read in 'd':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | 64 | ?? | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
5. Read in 'y':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | 64 | 79 | 01 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
6. Read in '\r\n' (or on UNIX, just '\n'), but this isn't put into the memory.
Instead, cin realizes that it has finished reading, and closes off the string with a '\0':
+----+----+----+----+----+----+----+----+----+
| 48 | 61 | 72 | 64 | 79 | 00 | 00 | 00 | 00 |
+----+----+----+----+----+----+----+----+----+
\________ s[5] ________/ \____ counter ____/
Whoops! 哎呀! It overwrote the counter!
它覆盖了柜台!
Why does it work correctly on Linux? 为什么在Linux上可以正常使用? Either Linux doesn't place the two variables adjacent in memory, or the Linux system is big-endian, which would mean the memory is instead laid out like this:
Linux不会在内存中将两个变量相邻放置,或者Linux系统是big-endian,这意味着内存的布局应如下所示:
+----+----+----+----+----+----+----+----+----+
| ?? | ?? | ?? | ?? | ?? | 00 | 00 | 00 | 01 |
+----+----+----+----+----+----+----+----+----+
So even if you read in 5 characters, the final null terminator just replaces a 0 that was already there. 因此,即使您读了5个字符,最终的空终止符也只会替换已经存在的0。 Of course, if this is the cause, then reading in 6 characters would really mess things up.
当然,如果这是原因,那么用6个字符读起来确实会使事情搞砸。
And how do you fix it? 以及如何解决? The problem is that, to hold a string of length
n
, a character array needs to have a length of n+1
. 问题在于,要容纳长度为
n
的字符串,字符数组的长度必须为n+1
。 So you could do this: 因此,您可以这样做:
char s[6];
Or even better, use a string: 甚至更好,使用字符串:
std::string s;
(For that you need to #include <string>
.) (为此,您需要
#include <string>
。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.