“” +在C ++中的东西 [英] "" + something in C++

查看:285
本文介绍了“” +在C ++中的东西的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在我的代码中发生了很奇怪的事情。我相信我已经跟踪到标记为here的部分(代码被简化,当然):

  std :: string func(){
char c;
//做分配给c
的东西return+ c; // Here
}

当我尝试<$ c时会发生各种事情$ c> cout 这个函数的结果。我想我甚至设法得到一些底层的C ++文档,以及许多细分错误。对我来说这显然不适用于C ++(我已经诉诸使用 stringstream 来执行转换 string 现在),但我想知道为什么。在使用大量的C#相当长一段时间后,没有C ++,这使我很痛苦。

解决方案


  • 是一个字符串文字。那些具有数组N const char 。这个特殊的字符串是一个数组1 const char ,一个元素是null终止符。


  • 数组很容易衰减成指向它们的第一个元素的指针,例如


  • lhs + rhs 未定义为 lhs 和整数 rhs


  • char 是C ++核心语言的一个整数数据类型(即,作为整数)。




==> string literal + 字符因此被解释为指针 + integer



表达式+ c 大致相当于:

  static char const lit [1] = {'\0'}; 
char const * p =& lit [0];
p + c //+ c大致相当于这个表达式






您返回 std :: string 。表达式+ c 产生指向 const char 的指针。 std :: string 的构造函数期望一个 const char * 期望它是一个指向null终止字符数组。



如果 c!= 0 ,则表达式+ c 会导致未定义的行为:




  • c& 1 ,指针运算产生未定义行为。


  • 如果 char 已签名,则 c < c>,指针运算不会产生未定义的行为。这是一个特殊情况;指向一个元素超过数组的最后一个元素是允许的(它是不允许使用它指向的,虽然)。它仍然导致未定义的行为,因为 std :: string 构造函数在这里调用要求其参数是一个指向有效数组(和一个以null结束的字符串)的指针。一个过去的元素不是数组本身的一部分。违反此要求也会导致UB。







std :: string 的构造函数试图通过搜索数组中的第一个字符来确定传递它的以null结束的字符串的大小到'\0'

 
{
// simplified
char const * end = p;
while(* end!='\0')++ end;
// ...
}

,或者它创建的字符串包含垃圾。
也可能编译器假设这个未定义的行为将永远不会发生,并做一些有趣的优化,将导致奇怪的行为。






顺便说一下, clang ++ 3.5会为此代码段发出一个很好的警告: / p>


警告:向字符串添加'char'不会附加到字符串
[-Wstring-plus-int] p>

  return+ c; // Here 
~~~ ^ ~~

注意:使用数组索引警告



I've been having really freaky stuff happening in my code. I believe I have tracked it down to the part labeled "here" (code is simplified, of course):

std::string func() {
    char c;
    // Do stuff that will assign to c
    return "" + c; // Here
}

All sorts of stuff will happen when I try to cout the result of this function. I think I've even managed to get pieces of underlying C++ documentation, and many a segmentation fault. It's clear to me that this doesn't work in C++ (I've resorted to using stringstream to do conversions to string now), but I would like to know why. After using lots of C# for quite a while and no C++, this has caused me a lot of pain.

解决方案

  • "" is a string literal. Those have the type array of N const char. This particular string literal is an array of 1 const char, the one element being the null terminator.

  • Arrays easily decay into pointers to their first element, e.g. in expressions where a pointer is required.

  • lhs + rhs is not defined for arrays as lhs and integers as rhs. But it is defined for pointers as the lhs and integers as the rhs, with the usual pointer arithmetic.

  • char is an integral data type in (i.e., treated as an integer by) the C++ core language.

==> string literal + character therefore is interpreted as pointer + integer.

The expression "" + c is roughly equivalent to:

static char const lit[1] = {'\0'};
char const* p = &lit[0];
p + c // "" + c is roughly equivalent to this expression


You return a std::string. The expression "" + c yields a pointer to const char. The constructor of std::string that expects a const char* expects it to be a pointer to a null-terminated character array.

If c != 0, then the expression "" + c leads to Undefined Behaviour:

  • For c > 1, the pointer arithmetic produces Undefined Behaviour. Pointer arithmetic is only defined on arrays, and if the result is an element of the same array.

  • If char is signed, then c < 0 produces Undefined Behaviour for the same reason.

  • For c == 1, the pointer arithmetic does not produce Undefined Behaviour. That's a special case; pointing to one element past the last element of an array is allowed (it is not allowed to use what it points to, though). It still leads to Undefined Behaviour since the std::string constructor called here requires its argument to be a pointer to a valid array (and a null-terminated string). The one-past-the-last element is not part of the array itself. Violating this requirement also leads to UB.


What probably now happens is that the constructor of std::string tries to determine the size of the null-terminated string you passed it, by searching the (first) character in the array that is equal to '\0':

string(char const* p)
{
    // simplified
    char const* end = p;
    while(*end != '\0') ++end;
    //...
}

this will either produce an access violation, or the string it creates contains "garbage". It is also possible that the compiler assumes this Undefined Behaviour will never happen, and does some funny optimizations that will result in weird behaviour.


By the way, clang++3.5 emits a nice warning for this snippet:

warning: adding 'char' to a string does not append to the string [-Wstring-plus-int]

return "" + c; // Here
       ~~~^~~

note: use array indexing to silence this warning

这篇关于“” +在C ++中的东西的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆