什么是空终止字符串 (string null terminator)

它与std::string有何不同?

它与std::string有何不同?

133

“string”实际上只是一个chars 的数组;以 null 结尾的字符串是一个空字符'\0'标记字符串结尾的字符串(不一定是数组的结尾)。编译器会自动以 null 结尾代码中的所有字符串(由双引号""分隔)。

例如,"hi"{'h', 'i', '\0'}相同。

51

null 终止的字符串是一个连续的字符序列,其中最后一个具有二进制比特模式全零。我不确定你所说的“普通字符串”是什么意思,但是如果你的意思是std::string,那么一个std::string是不需要的 (until C++11) 是连续的,并且不需要有这样的终止符std::string

所有这些都应该在任何体面的 C ++ 教科书中涵盖-我建议掌握Accelerated C++,其中最好的一个。

16

有两种主要的方式来表示一个字符串:

1) 末尾带有 ASCII null (nul) 字符 0 的字符序列。你可以通过搜索终止符来判断它有多长。这被称为以 null 结尾的字符串,或者有时以 nul 结尾。

2)一个字符序列,再加上一个单独的字段(可以是整数长度,也可以是指向字符串末尾的指针),以告诉您它有多长。

我不确定“通常的字符串”,但是经常发生的是,在谈论特定语言时,“string”一词用于表示该语言的标准表示形式。因此,在 Java 中,java.lang.String 是类型 2 的字符串,因此这就是“string”的含义。在 C 中,“string”可能表示类型 1 的字符串。为了精确,标准非常冗长,但是人们总是希望省略“显而易见的”。

不幸的是,在 C ++ 中,这两种类型都是标准的。std::string 是类型 2 字符串 [*],但从 C 继承的标准库函数对类型 1 字符串进行操作。

[*] 实际上,std::string 通常被实现为字符数组,具有单独的长度字段nul 终止符。这使得c_str()函数可以在不需要复制或重新分配字符串数据的情况下实现。我不记得在不存储长度字段的情况下实现 std::string 是否合法:问题是

9
'\0' 

是 ASCII 字符,代码为 0,null 终止符,null 字符,NUL。在C语言中,它用作保留字符,用于表示字符串的结尾。许多标准函数,例如 strcpy,strlen,strcmp 等都依赖于此。否则,如果没有NUL,则必须使用另一种方式来表示字符串的结尾:

这允许字符串是任何长度,只有一个字节的开销;存储计数的替代方案需要 255 的字符串长度限制或超过一个字节的开销。

from

C++std::string遵循另一种约定,其数据由名为_Rep的结构表示:

// _Rep: string representation
      //   Invariants:
      //   1. String really contains _M_length + 1 characters: due to 21.3.4
      //      must be kept null-terminated.
      //   2. _M_capacity >= _M_length
      //      Allocated memory is always (_M_capacity + 1) * sizeof(_CharT).
      //   3. _M_refcount has three states:
      //      -1: leaked, one reference, no ref-copies allowed, non-const.
      //       0: one reference, non-const.
      //     n>0: n + 1 references, operations require a lock, const.
      //   4. All fields==0 is an empty string, given the extra storage
      //      beyond-the-end for a null terminator; thus, the shared
      //      empty string representation needs no constructor.
      struct _Rep_base
      {
    size_type       _M_length;
    size_type       _M_capacity;
    _Atomic_word        _M_refcount;
      };
struct _Rep : _Rep_base
      {
    // Types:
    typedef typename _Alloc::template rebind<char>::other _Raw_bytes_alloc;
    // (Public) Data members:
    // The maximum number of individual char_type elements of an
    // individual string is determined by _S_max_size. This is the
    // value that will be returned by max_size().  (Whereas npos
    // is the maximum number of bytes the allocator can allocate.)
    // If one was to divvy up the theoretical largest size string,
    // with a terminating character and m _CharT elements, it'd
    // look like this:
    // npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
    // Solving for m:
    // m = ((npos - sizeof(_Rep))/sizeof(CharT)) - 1
    // In addition, this implementation quarters this amount.
    static const size_type  _S_max_size;
    static const _CharT _S_terminal;
    // The following storage is init'd to 0 by the linker, resulting
        // (carefully) in an empty string with one reference.
        static size_type _S_empty_rep_storage[];
        static _Rep&
        _S_empty_rep()
        { 
      // NB: Mild hack to avoid strict-aliasing warnings.  Note that
      // _S_empty_rep_storage is never modified and the punning should
      // be reasonably safe in this case.
      void* __p = reinterpret_cast<void*>(&_S_empty_rep_storage);
      return *reinterpret_cast<_Rep*>(__p);
    }
        bool
    _M_is_leaked() const
        { return this->_M_refcount < 0; }
        bool
    _M_is_shared() const
        { return this->_M_refcount > 0; }
        void
    _M_set_leaked()
        { this->_M_refcount = -1; }
        void
    _M_set_sharable()
        { this->_M_refcount = 0; }
    void
    _M_set_length_and_sharable(size_type __n)
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
        {
          this->_M_set_sharable();  // One reference.
          this->_M_length = __n;
          traits_type::assign(this->_M_refdata()[__n], _S_terminal);
          // grrr. (per 21.3.4)
          // You cannot leave those LWG people alone for a second.
        }
    }
    _CharT*
    _M_refdata() throw()
    { return reinterpret_cast<_CharT*>(this + 1); }
    _CharT*
    _M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2)
    {
      return (!_M_is_leaked() && __alloc1 == __alloc2)
              ? _M_refcopy() : _M_clone(__alloc1);
    }
    // Create & Destroy
    static _Rep*
    _S_create(size_type, size_type, const _Alloc&);
    void
    _M_dispose(const _Alloc& __a)
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
        if (__gnu_cxx::__exchange_and_add_dispatch(&this->_M_refcount,
                               -1) <= 0)
          _M_destroy(__a);
    }  // XXX MT
    void
    _M_destroy(const _Alloc&) throw();
    _CharT*
    _M_refcopy() throw()
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
      return _M_refdata();
    }  // XXX MT
    _CharT*
    _M_clone(const _Alloc&, size_type __res = 0);
      };

实际数据可以通过以下方式获得:

_Rep* _M_rep() const
      { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }

此代码片段来自文件basic_string.h,该文件在我的计算机上位于usr/include/c++/4.4/bits/basic_string.h

正如你所看到的,差异是显著的。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处

(659)
Java中的十进制到十六进制转换器
上一篇
Java中的十进制到十六进制转换器
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(6条)