【问题标题】:Can a string literal and a character literal be concatenated?字符串文字和字符文字可以连接吗?
【发布时间】:2010-10-12 18:10:24
【问题描述】:

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

string name =  "ab"+'c';

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

【问题讨论】:

  • 为什么不直接做 std::cout
  • 由于 java 和 C# 都不使用 cout,它们的行为是抛出编译错误
  • "ab" 不是字符串,而是 c++ 中的 char*,不能使用 + 运算符连接。
  • 我只是想知道发生了什么
  • 您想了解 C++ 还是 C#?您将其标记为 C++,但在问题中提到了 C#。

标签: c# java c++ string char


【解决方案1】:

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

这在 C# 中工作得很好:

string test = "foo" + 'b';

【讨论】:

  • 不是严格,只是字符串在 C++ 中技术上不存在
【解决方案2】:

试试

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”

【讨论】:

  • 这不是一回事。原版中没有任何关于 I/O 的内容。他可能想要将它们连接起来,以便为信号量或其他东西创建名称。
  • 该问题与原始问题相比发生了显着变化。我进行了编辑以反映更改。
  • 我刚才正要编辑原来的问题,所以使用 std::cout 的答案是有意义的,但看起来这是最后一个。
【解决方案3】:

Java:

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

输出是:

ABc

编辑:

实际上编译器硬编码 String ABc...

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

StringBuilder b = new StringBuilder;
b.append("AB");
b.append(argv[0].charAt(0));
System.out.println(b.toString());

【讨论】:

  • 您忘记了输出中的“\n”。它是 println() 而不是 print() :)
  • 这里实际发生的是,在 + 操作之前将 char 文字转换为字符串文字,然后从 "AB" 和 (String)'c' 字符串文字生成一个新字符串.
  • @OTisler 朋友之间有什么额外的换行符? :-P
  • 已更新以包含换行符 :-P 并显示编译时发生的情况
  • 删除了我之前的误导性评论。
【解决方案4】:

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

T operator+ (const char*, char);

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

【讨论】:

  • 它找到了一个,但它不是你想要的那个。你最终得到的是指针运算而不是字符串连接。
  • 好点。但是现在这个问题已经改变了很多次,我已经忘记了他在问什么。
【解决方案5】:

问题是“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) 连接在一起,但编译器甚至不会查找它,因为第一个参数不是 std::string。

所以解决办法是手动创建字符串:

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

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

【讨论】:

  • 投了赞成票,虽然我觉得我更喜欢你的原作。在 C 中,数组和指针之间基本上没有区别(可能除了分配/释放问题)。所以它不像“尝试两者”。
【解决方案6】:

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";

【讨论】:

    【解决方案7】:

    给定 C++ 代码:

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

    Java 中的等价物是:

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

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

    【讨论】:

    • 它不是未定义的。它只是将'c'的整数值添加到指向静态分配的字符数组{'a','b'}的指针。当然,结果是未定义的,但这只是因为您最终指向了数组。实际的 + 操作是完美定义的
    • 我相信指针超出数组+1的行为是未定义的。
    【解决方案8】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2019-07-13
      • 2023-03-27
      • 1970-01-01
      • 2015-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-19
      • 2014-09-11
      相关资源
      最近更新 更多