简体   繁体   English

在Windows中编译的C ++程序产生不同的输出

[英]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.

相关问题 C++ Windows 编译程序与 Linux 的行为不同 - C++ Windows compiled program different behaviour to Linux C ++控制台模式程序在Mac和Windows上产生不同的结果 - C++ console-mode program produces different result on Mac to Windows 不明白为什么C ++程序不产生输出 - Do not understand why C++ program produces no output c ++将函数输出重定向到编译的程序输入,反之亦然 - c++ Redirect function output to compiled program input and viceversa 如何查看在终端上编译的C ++程序的输出 - How to view the output of c++ program which compiled on terminal 编译的c ++输出文件在程序结尾显示随机字符吗? - Compiled c++ output file displays random character at end of program? Java和C ++中的类似程序的不同输出 - Similar program in java and c++ different output 我应该如何向生成终端输出的 C++ 程序添加固定进度条(在 Linux 中)? - How should I add a stationary progress bar to a C++ program that produces terminal output (in Linux)? 编写一个程序,如果编译为 (ANSI) C 程序,将打印“C”,如果编译为 C++ 程序,将打印“C++” - Write a program that will print “C” if compiled as an (ANSI) C program, and “C++” if compiled as a C++ program C ++程序的输出 - Output of a c++ program
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM