【问题标题】:How do I find 8-bit substrings in strings with ascii values exceeding 127?如何在 ascii 值超过 127 的字符串中找到 8 位子字符串?
【发布时间】:2020-12-06 02:52:32
【问题描述】:

我正在努力解决我在尝试使用字符串中的按位子字符串时遇到的问题。在下面的示例中,这个简单的小函数对值 0-127 执行了应有的操作,但如果我尝试使用大于 127 的 ASCII 值,则会失败。我认为这是因为字符串本身已签名。但是,如果我将其设为无符号,我不仅会遇到问题,因为显然strlen() 不会对无符号字符串进行操作,而且我会收到警告说它是一个多字符常量。为什么是多个字符?我想我已经尝试了一切。我可以做些什么来使这个值> 127?

#include <iostream>
#include <cstring>

const unsigned char DEF_KEY_MINOR = 0xAD;

const char *buffer = { "jhsi≠uhdfiwuui73" };

size_t isOctetInString(const char *buffer, const unsigned char octet)
{
  size_t out = 0;
  for (size_t i = 0; i < strlen(buffer); ++i)
  {
    if(!(buffer[i] ^ octet))
    {
      out = i;
      break;
    }
  }
  return out;
}

int main() {
    std::cout << isOctetInString(buffer, 'i') << "\n";
    std::cout << isOctetInString(buffer, 0x69) << "\n";
    std::cout << isOctetInString(buffer, '≠') << "\n";
    std::cout << isOctetInString(buffer, 0xAD) << "\n";
    return 0;
}

输出

3
3
0
0

编辑

基于 cmets,我尝试了一些不同的方法,包括将八位字节和缓冲区转换为 unsigned int 和 wchar_t,以及从八位字节参数类型中删除 unsigned char。有了这些,我得到的输出是

3
3
6
0

我什至尝试将缓冲区中的 ≠ char 替换为

const char *buffer = {'0xAD', "jhsiuhdfiwuui73"};

但是我仍然收到有关多字节字符的警告。

正如我之前所说,我主要关心的是能够在字符串中找到位序列 0xAD,但我现在看到使用 ascii 字符或任何使用 ascii 字符集的构造都会导致问题。由于0xAD 只有 8 位,所以一定有办法做到这一点。有谁知道这样做的方法吗?

【问题讨论】:

  • ASCII 是 7 位编码,因此没有 ASCII 值 >127。 在 .cpp 文件中的编码和解释方式取决于您使用的文本编辑器和编译器。
  • 我实际上只关心位。我只是想测试算法。该符号可能不可移植,但这是该环境的正确符号。
  • 然后只强制比较单个字节(unsigned char)buffer[i] == (unsigned char)octet。但是,关于“multi-char constant”的警告表明可能涉及其他一些多字节编码,可能是 UTF-8。
  • bufferoctet 都需要签名(或两者都未签名)。否则,0xAD 的符号扩展将给出0xFFFFFFAD(有符号,32 位整数)和0x000000AD(无符号,32 位整数)。对这些进行异或运算将得到0xFFFFFF00
  • 如果在您的平台上char 被签名,则设置高位时的实际值将在-128 和-1 之间。用 128 到 255 之间的数字对此类值进行异或运算永远不会给出 0。

标签: c++ string search substring bit-manipulation


【解决方案1】:

符号扩展 -- buffer[i]^octet 实际上是 unsigned(int(buffer[i])) ^ unsigned(octet)。如果你希望 buffer[] 是 unsigned char,你必须这样定义它。

【讨论】:

    【解决方案2】:

    您的问题有多种混淆来源:

    • 可以使用strchr() 在字符串中搜索unsigned char 值,它将int 参数和char 数组中的字符都转换为unsigned char 以进行比较。

    • 您的函数使用if(!(buffer[i] ^ octet)) 来检测匹配,如果char 已签名,则该匹配不起作用,因为表达式被评估为if(!((int)buffer[i] ^ (int)octet)),并且符号扩展仅适用于buffer[i]。一个简单的解决方案是:

        if ((unsigned char)buffer[i] == octet)
      
    • 请注意,在源代码和终端处理中,字符 可能在您的目标系统上被编码为多个字节,例如代码点 是 8800 或 0x2260 被编码为UTF-8 中的 0xE2 0x89 0xA0。语法'≠' 会带来问题。我不确定 C++ 如何处理多字节字符常量,但 C 会接受具有特定实现值的它们。

    • 要查看您的系统如何处理非 ASCII 字节,您可以将这些行添加到您的 main() 函数中:

        std::cout << "≠ uses " << sizeof("≠") - 1 << "bytes\n";
        std::cout << "'≠' has the value " << (int)'≠' << "\n";
      

      或更明确地说:

        printf("≠ is encoded as");
        for (size_t i = 0; i < sizeof("≠") - 1; i++) {
            printf(" %02hhX", "≠"[i]);
        }
        printf(" and '≠' has a value of 0x%X\n", '≠');
      

      在我的 linux 系统上,后者输出:

       ≠ 被编码为 E2 89 A0 并且 '≠' 的值为 0xE289A0

      在我的 MacBook 上,编译失败并出现以下错误:

        notequal.c:8:48: error: character too large for enclosing character literal type
        printf(" and '≠' has a value of 0x%X\n", '≠');
      

    【讨论】:

      猜你喜欢
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 2016-09-14
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多