【问题标题】:Get bytes from std::string in C++从 C++ 中的 std::string 获取字节
【发布时间】:2009-02-02 21:28:58
【问题描述】:

我在一个 C++ 非托管项目中工作。

我需要知道如何获取像“一些要加密的数据”这样的字符串并获得一个字节[] 数组,我将使用它作为 Encrypt 的源。

在 C# 中我会这样做

  for (int i = 0; i < text.Length; i++)
    buffer[i] = (byte)text[i];

我需要知道的是如何使用非托管 C++ 做同样的事情。

谢谢!

【问题讨论】:

    标签: c++ string


    【解决方案1】:

    如果你只需要只读权限,那么c_str() 就可以了:

    char const *c = myString.c_str();
    

    如果您需要读/写访问权限,则可以将字符串复制到向量中。向量为您管理动态内存。那么你不必搞乱分配/解除分配:

    std::vector<char> bytes(myString.begin(), myString.end());
    bytes.push_back('\0');
    char *c = &bytes[0];
    

    【讨论】:

    • 如果他想要一个字节数组,他需要终止'\0'吗?在这种情况下,您可以将 data() 用于只读。
    • 我不确定他是否需要 \0。如果他不这样做,他现在知道他可以使用 .data() 。感谢您对此发表评论,马丁。
    • 这个答案似乎正确并且可能有效,但假设 char 向量的数据存储是连续的并且不会改变是危险的。
    • 假设它是连续的一点也不危险,它是向量的保证(C++ 规范 IIRC 中 std::vector 下的第一段)。假设它不会改变是安全的,前提是某些指定的函数没有被调用——相当于那些可能引发 resize() 的函数。
    • 马克,“假设”这一点是非常安全的,因为向量总是连续的 :) 并且假设指针是有效的也是安全的。您不会修改向量,因此它必须重新分配其缓冲区。所以向量的第一个元素地址当然保持不变。
    【解决方案2】:

    std::string::data 似乎是足够且最有效的。如果您想使用非常量内存来操作(加密很奇怪),您可以使用 memcpy 将数据复制到缓冲区:

    unsigned char buffer[mystring.length()];
    memcpy(buffer, mystring.data(), mystring.length());
    

    STL 粉丝会鼓励您改用 std::copy

    std::copy(mystring.begin(), mystring.end(), buffer);
    

    但这确实没有太大的好处。如果您需要空终止,请使用std::string::c_str() 和其他人提供的各种字符串复制技术,但我通常会避免这种情况,只需查询length。特别是对于密码学,您只知道有人会尝试通过将空值插入其中来尝试破解它,并且使用 std::string::data() 会阻止您懒惰地对字符串中的底层位进行假设。

    【讨论】:

    • 您能否说明使用 string::data() 比使用 string::begin() 更好?一个返回指向底层存储的指针,另一个返回一个迭代器,这对安全性有何帮助?
    • 可变长度数组,如 unsigned char buffer[mystring.length()] 不是标准 C++。一些编译器支持它们,但 Visual Studio 不支持。
    【解决方案3】:

    通常,加密函数需要

    encrypt(const void *ptr, size_t bufferSize);
    

    作为参数。可以直接传递 c_str 和 length:

    encrypt(strng.c_str(), strng.length());
    

    这样,额外的空间被分配或浪费。

    【讨论】:

    • 如果你传递一个指针和一个长度,那么你应该使用 data() 而不是 c_str() 来表明它没有被用作字符串。
    【解决方案4】:

    如果您想获取 char_t 缓冲区指针,可以从 std::string 使用 c_ptr() 方法。

    看起来你只是想将字符串的字符复制到一个新的缓冲区中。我会简单地使用std::string::copy 函数:

    length = str.copy( buffer, str.size() );
    

    【讨论】:

    • 某些 std::string 的实现可能会使用引用计数,因此副本不一定会产生可以安全写入的新字节。
    【解决方案5】:

    如果你只是需要读取数据。

    encrypt(str.data(),str.size());
    

    如果您需要数据的读/写副本,请将其放入向量中。 (不要动态分配空间,这是向量的工作)。

    std::vector<byte>  source(str.begin(),str.end());
    encrypt(&source[0],source.size());
    

    当然我们都假设字节是一个字符!!!

    【讨论】:

      【解决方案6】:

      C++17 及以后你可以使用std::byte 来表示实际的字节数据。我会推荐这样的东西:

      std::vector<std::byte> to_bytes(std::string const& s)
      {
          std::vector<std::byte> bytes;
          bytes.reserve(std::size(s));
            
          std::transform(std::begin(s), std::end(s), std::back_inserter(bytes), [](char c){
              return std::byte(c);
          });
      
          return bytes;
      }
      

      【讨论】:

      • 其实 std::byte 并没有出现在 C++11 中,而是出现在 C++17 中。见en.cppreference.com/w/cpp/types/byte
      • @Nikita128 非常正确,感谢您指出这一点。现已修复!
      【解决方案7】:

      如果这只是普通的 C,那么:

      strcpy(buffer, text.c_str());
      

      假设缓冲区已分配并且足够大以容纳“文本”的内容,这是您原始代码中的假设。

      如果 encrypt() 采用 'const char *' 那么你可以使用

      encrypt(text.c_str())
      

      而且你不需要复制字符串。

      【讨论】:

        【解决方案8】:

        你可以使用range-based for 循环,看起来像这样:

        std::vector<std::byte> getByteArray(const string& str)
        {
            std::vector<std::byte> buffer;
            for (char str_char : str)
                buffer.push_back(std::byte(str_char));
        
            return buffer;
        }
        

        【讨论】:

          【解决方案9】:

          我认为您不想使用那里的 c# 代码。他们提供 System.Text.Encoding.ASCII(也是 UTF-*)

          string str = "some text;
          byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);
          

          您的问题源于忽略 c# 中的编码而不是您的 c++ 代码

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-09-24
            • 1970-01-01
            • 1970-01-01
            • 2011-09-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多