我不明白我的编译器是如何得到这个输出的

I don't understand how my compiler got this output

请注意,我使用的是 Turbo C++ 编译器,因为我们的学校教学大纲应该只学习 Turbo C++。这就是为什么在这种情况下 cout 语句从右到左计算的原因。

计划

#include <iostream.h>
#include <string.h>

void func(char *s, char t[]) {
    strcpy(t, "Have fun");
    s = "Be[=10=]Cool";
    cout << s[0] << ++s << s++ << --s << strupr(s+2) << ++s << s++ << s;
}

int main() {
    char x[] = "Hello World!!!", y[] = "Hello World";
    func(x, y);
    cout << x << y;
    return 0;
}

输出

CCOOLeeOOLBeBeHello World!!!Have fun


我觉得输出应该是:

CCooleeOOLBeBeHello World!!!Have fun

因为在cout语句的++s部分(第二个位置),指针在字符串[=14=的索引3处],所以只应打印 'Cool'。相反 'COOL' 正在打印。为什么会这样?

测试 Visual Studio 2019

为了比较,在 Visual Studio 2019 (DEBUG) 中,如果我们进行必要的更改来编译代码,那么程序会崩溃,因为我们试图修改常量字符串 ("Be[=12=]Cool")。

如果我们进行额外的更改以避免崩溃(通过使用本地数组),输出为:

CCoOLeCoOLOLCoOLBeCoOLHello World!!!Have fun

如果我们将 cout << s[]…; 行拆分为对 cout 的多次调用(每个 << 之前调用一次),那么输出将是:

BeeeCOOLCOOLHello World!!!Have fun

或者如果我们在每个输出后添加一行,我们得到:

B
e
e
e
COOL


COOL
Hello World!!!
Have fun

试图理解 Turbo C++ 的输出

如果我们然后反转对 cout 的每个调用以从最后一个(即 cout << s<< endl;)开始并从第一个(cout << s[0] << endl)结束,那么我们得到:

Be
Be

OOL
e
e
COOL
C
Hello World!!!
Have fun

如果我们手动从倒数第三行开始写,然后按顺序写到最后两行,没有 space,我们得到:

CCOOLeeOOLBeBeHello World!!!Have fun

这正是您得到的输出结果。

因此,Turbo C++ 似乎从右到左计算每个表达式。

有关编译所需更改的说明(和 运行)

  • <iostream.h> 不可用,所以我必须改用 <iostream>
  • #define _CRT_SECURE_NO_WARNINGS 必须在顶部添加,因为某些功能不安全(默认情况下不会编译)。
  • using namespace std; 以避免对代码进行更多更改。
  • s = (char *)"Be[=22=]Cool"; 中添加强制转换,以便编译该行。
    • 这会导致崩溃,因为数据是常量,我们会尝试修改它。
  • 删除演员表,改写 char data[] = "Be[=23=]Cool"; s = data;
    • 程序运行但是输出是CCoOLeCoOLOLCoOLBeCoOLHello World!!!Have fun
    • 事实上,这是未定义的行为。它恰好是实际输出。

未定义的行为

有些东西没有被标准定义,因此不需要以某种方式工作。好吧,如果不支持只读内存,它就像读写内存一样工作。

对于评估顺序,常见的可能性是:

  • 从左到右
  • 从右到左
  • 哪个更优

另外,由于一个变量被修改了不止一次,s 的值在计算期间和之后都没有定义。容易记住的规则是避免在单个表达式中多次修改同一个变量。

关于strupr

该函数将字符串修改为终止空字符。在您的情况下,它会将 s 在调用时具有的任何值的每个字母转换为大写。