4

为什么name在以下 C++ 代码中行为不端?

string name =  "ab"+'c';

等效代码在 Java/C# 中的行为如何?

4

8 回答 8

13

尝试

std::string name = "ab" "c";

或者

std::string name = std::string("ab") + c;

在 C++ 中,“ab”不是一个std::string,而是一个指向字符串的指针。当您将整数值添加到指针时,您会得到一个指向字符串下方更远的新指针:

char *foo = "012345678910121416182022242628303234";
std::string name = foo + ' '; 

name设置为“3234”,因为 ' ' 的整数值为 32 并且 foo 开头之后的 32 个字符是字符串结尾之前的四个字符。如果字符串较短,您将尝试访问未定义内存区域中的某些内容。

解决方案是从字符数组中创建一个 std:string 。std:strings 允许您按预期将字符附加到它们:

std::string foo = "012345678910121416182022242628303234";
std::string name = foo + ' '; 

name设置为“012345678910121416182022242628303234”

于 2009-03-11T18:40:57.940 回答
8

问题是“ab”不是 C++ std::string,而是const char[3]. 所以它正在寻找的 + 运算符是operator+ (const char[3], char). 那不存在,因此编译器尝试让数组衰减为指针,因此它会查找operator+ (const char*, char). 那是存在的,所以编译器会选择它,但它做错了。将整数值(char)添加到指针(const char*)是很常见的操作,显然,这就是 operator+ 所做的。理解这一点的关键是要认识到第一个参数是 1) 一个数组,以及 2) 一个指针,只要数组没有意义。它也被用作 C 中的字符串,是的,但它不是字符串。它是一个指针(或者偶尔是一个数组)。

有一个operator+ (const std::string&, char)which 连接,但编译器甚至不会查找它,因为第一个参数不是 std::string。

所以一个解决方案是手动创建字符串:

string name = std::string("ab")+'c';

现在编译器可以找出正确的 operator+ 来调用。

于 2009-03-11T18:49:29.870 回答
5

在 C++ 中,编译器正在寻找具有此原型的函数:

T operator+ (const char*, char);

由于没有,它无法弄清楚 T 是什么并且无法解析operator<<调用,所以它回退到唯一剩下的解决方案:指针加法。像 Josh 的回答那样连接到字符串没有问题,因为它存在一个函数。

于 2009-03-11T18:44:39.337 回答
3

给定 C++ 代码:

std::string name =  "ab"+'c';

Java中的等价物是:

String name = "ab".substring('c');

两者都将 char 提升为 int。当然,在 Java 中,它会进行范围检查,因此会引发异常。在 C++ 中,您只会得到未定义的行为(或类似行为)。

于 2009-03-11T19:36:19.383 回答
2

爪哇:

public class Main
{
    public static void main(String[] args)
    {
        System.out.println("AB" + 'c');
    }
}

输出是:

ABC

编辑:

实际上编译器硬编码字符串 ABc ......

如果你做 "AB" + argv[0].charAt(0); 让它使用一个变量然后编译器这样做(基本上):

StringBuilder b = new StringBuilder;
b.append("AB");
b.append(argv[0].charAt(0));
System.out.println(b.toString());
于 2009-03-11T18:43:01.103 回答
1

您可以在 C# 中连接字符串和字符 - 我猜它不像 C++ 那样严格。

这在 C# 中工作得很好:

string test = "foo" + 'b';
于 2009-03-11T18:39:46.603 回答
1

C++ 编译器不会自动将字符串文字与字符文字连接起来。但它会将字符串文字彼此连接起来。语法是这样的:

const char * cs = "ab" "c"; // append string-literals

正如其他人所提到的,string它不是内置的C++ 语言类型。但是 C++ 标准库中有一个string类型。以下是一些使用示例:

#include <string>
const char * cs = "ab" "c";
std::string s1( cs );
std::string s2( "ab" "c" );
std::string s3 = "ab" "c";
于 2009-03-11T19:19:32.623 回答
1

好吧,我通常会在 C++ 中做的是

字符串名称 = string("ab") +'c';

请记住,文字“ab”不是字符串类型。您所做的是希望在 char 数组和字符之间没有“+”,然后希望编译器能够以某种方式注意到您确实希望结果是 std::string,然后解析您的表达式右侧是一些隐式转换的组合,可以与运算符组合以产生该类型的结果。对我来说似乎是一个相当高的要求。

不管怎样,没关系。你看,在 C 中,数组和指针之间的唯一区别是它们的内存是如何分配的。一旦你有了一个,你基本上就有了一个“数组/指针的东西”。因此,“+”是在所有数组和指针上定义的运算符,它接受任何整数类型的另一个参数并进行指针数学运算,返回指向该点之后那么多元素的指针。此外,在 C 中,“char”实际上只是另一种整数类型。这些 C 设计决策都是有用的hack,但正如 hack 经常发生的那样,它们结合了直观意想不到的结果。因此,所有 "ab" + 'c' 为您所做的就是返回一个地址 99 个字节,只要 "ab" 文字恰好存储在内存中。

有时您可以依赖隐式转换,但您确实必须准备好在其他时候帮助您的编译器。

于 2009-03-11T22:41:48.517 回答