【发布时间】:2021-01-11 07:27:29
【问题描述】:
我有一个 C++ 程序:
#include <iostream>
char * foo (char * bar, const char * baz) {
int i = -1;
do {
i++;
*(bar + i) = *(baz + i);
} while (*(baz + i));
return bar;
}
int main (int argc, char *argv[]) {
char bar[] = "";
char baz[] = "Hello";
foo(bar, baz);
std::cout << "bar: " << bar << std::endl;
std::cout << "baz: " << baz << std::endl;
}
这不是重要的部分,但这个程序的要求是它使用指针将一个C style string复制到另一个。
当我在我的 Ubuntu 16.04 桌面上编译并执行我的二进制文件时,我看到的是:
$ g++ -std=c++11 test.cpp -o test && ./test
bar: Hello
baz: ello
埃加德! baz 的初始 'H' 已被删除,但我根本看不到我的 foo 函数如何更改 baz。嗯……
我的 Ubuntu 桌面上的 g++ 版本是这样的:
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
我认为这是我的代码的错误或错误(现在可能仍然如此),但我发现当我在任何其他操作系统上编译和运行时,我会得到不同的行为。
这是 macOS 上的输出:
$ g++ -std=c++11 test.cpp -o test && ./test
bar: Hello
baz: Hello
这是 macOS 笔记本电脑上的 g++ 版本:
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 12.0.0 (clang-1200.0.32.2)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
在其他 Linux 机器、Windows 等上进行测试时,它具有正确的预期输出 bar 和 baz 两者都是 Hello。
这是怎么回事!?
tl;dr C++ 程序在我的桌面上输出 C 样式字符串的方式与任何其他计算机不同。为什么?
【问题讨论】:
-
char bar[] = "";不是一个很大的字符串。将任何内容复制到其中可能会导致缓冲区溢出以及您的朋友和我的Undefined Behaviour。由于具有未定义行为的程序的行为是未定义的,因此推理不一致的行为是一种值得怀疑的时间消耗。.. -
旁注:您可能会发现
while (*baz) { *bar++ = *baz++; }对大脑更容易一些。虽然baz处有一个非零值,但获取baz处的值,然后将baz推进到下一个字符。将值存入bar处的值,然后前进bar。 -
您可能希望在
[和]之间指定bar的长度。 -
@user4581301:这个(尽管是规范的)循环的唯一问题是你必须在循环之后传输
\0。 -
Sleep,
do/while在这里工作得更好一些,因为 paxdiablo 的评论指出了一些原因。如果你测试空终止符并在复制空终止符后退出,你不必担心。