【问题标题】:Searching for 2 consecutive hex values in a char array of a file在文件的 char 数组中搜索 2 个连续的十六进制值
【发布时间】:2011-08-30 16:40:13
【问题描述】:

我已使用 fread 将文件读入字符数组。现在我想在该数组中搜索两个连续的十六进制值,即 FF 后跟 D9(它是一个表示文件结尾的 jpeg 标记)。这是我用来执行此操作的代码:

char* searchBuffer(char* b) {
    char* p1 = b;
    char* p2 = ++b;
    int count = 0;

    while (*p1 != (unsigned char)0xFF && *p2 != (unsigned char)0xD9) {
        p1++;
        p2++;
        count++;
    }

    count = count;
    return p1;
}

现在我知道,如果我搜索不包含 0xFF 的十六进制值(例如 4E 后跟 46),则此代码有效,但每次我尝试搜索 0xFF 时都会失败。当我不将十六进制值转换为 unsigned char 时,程序不会进入 while 循环,当我这样做时,程序会遍历数组中的所有字符并且不会停止,直到出现越界错误。我被难住了,请帮忙。

忽略计数,它只是一个帮助我调试的变量。

提前致谢。

【问题讨论】:

  • 我实际上不相信你的条件是正确的。不应该是!(*p1 == (unsigned char)0xFF && *p2 == (unsigned char)0xD9)吗? (暂且不说你对unsigned charunsigned int 的问题)正如目前所写的那样,你的循环似乎会在遇到0xFF 0xD9 时结束。
  • 你为什么不用strstr()
  • && 更改为 || 并阅读 Oli 的答案。
  • @Angel:因为 JPEG 文件不是 C 字符串。
  • 另请注意,您的代码存在处理格式错误数据的主要设计错误。它不将缓冲区的长度作为参数,因此如果未找到终止字节,它将愉快地运行超过缓冲区的末尾,从而导致 UB。您可以通过传递和测试长度来解决此问题,或者在从文件中读取缓冲区后始终将终止字节附加到缓冲区。

标签: c arrays search pointers hex


【解决方案1】:

为什么不使用memchr() 来查找潜在匹配项?

此外,请确保您正在处理可能已签名类型的促销活动(char 可能已签名也可能未签名)。请注意,虽然 0xff0xd9 设置为 8 位值时设置了高位,但它们是非负整数常量,因此它们不会发生“符号扩展”:

char* searchBuffer(char* b) {
    unsigned char* p1 = (unsigned char*) b;
    int count = 0;

    for (;;) {
        /* find the next 0xff char */
        /* note - this highlights that we really should know the size   */
        /* of the buffer we're searching, in case we don't find a match */
        /* at the moment we're making it up to be some large number     */
        p1 = memchr(p1, 0xff, UINT_MAX);
        if (p1 && (*(p1 + 1) == 0xd9)) {
            /* found the 0xff 0xd9 sequence */
            break;
        }

        p1 += 1;
    }

    return (char *) p1;
}

另外,请注意,您确实应该传递一些正在搜索的缓冲区大小的概念,以防找不到目标。

这是一个带有缓冲区大小参数的版本:

char* searchBuffer(char* b, size_t siz) {
    unsigned char* p1 = (unsigned char*) b;
    unsigned char* end = p1 + siz;

    for (;;) {
        /* find the next 0xff char */
        p1 = memchr(p1, 0xff, end - p1);
        if (!p1) {
            /* sequnce not found, return NULL */
            break;
        }


        if (((p1 + 1) != end) && (*(p1 + 1) == 0xd9)) {
            /* found the 0xff 0xd9 sequence */
            break;
        }

        p1 += 1;
    }

    return (char *) p1;
}

【讨论】:

  • 如果 memchr 返回 0(随后从 (unsigned char *)0+1 开始搜索),则您的代码存在重大错误。当然,在这种情况下,OP 的代码也被破坏(按设计)。
  • 另外,虽然在实践中它应该可以工作,但我认为像这样将UINT_MAX 传递给memchr 作为“未知大小”实际上会导致UB。根据标准,memchr 的缓冲区参数实际上必须是指定大小的对象。
  • @R.:在 cmets 中提到了未知缓冲区大小。我将发布一个带有大小参数的版本。
  • 确实,让我失望的是您正在检查某个位置的返回值是否为非空,但后来(在该条件之外)假设它是非空的。
【解决方案2】:

您违反了整数促销!=(和类似的)的两个操作数都提升为int。如果其中至少有一个是unsigned,那么它们都被视为unsigned(实际上这不是100% 准确,但对于这种特殊情况,它应该就足够了)。所以这个:

*p1 != (unsigned char)0xFF

相当于:

(unsigned int)*p1 != (unsigned int)(unsigned char)0xFF

在您的平台上,char 显然是signed,在这种情况下,它永远不会具有(unsigned int)0xFF 的值。

所以尝试如下投射*p1

(unsigned char)*p1 != 0xFF

或者,您可以让函数采用 unsigned char 参数而不是 char,并避免所有强制转换。

[请注意,除此之外,您的循环逻辑不正确,正如各种 cmets 中所指出的那样。]

【讨论】:

  • 感谢您花时间解释这一点:)
【解决方案3】:

4E 会将自身提升为正整数,但*p1 将在 FF 时为负数,然后将提升为远大于 FF 的非常大的无符号值。

你需要使p1无符号。

【讨论】:

    【解决方案4】:

    您可以将代码写得更短:

    char* searchBuffer(const char* b) {
        while (*b != '\xff' || *(b+1) != '\xd9') b++;
        return b;
    }
    

    还要注意,如果 b 实际上不包含字节 FFD9,该函数将导致分段错误(或更糟的是,返回无效结果)。

    【讨论】:

      【解决方案5】:

      使用 void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);

      在 string.h 中可用且易于使用。

      char* searchBuffer(char* b, int len) 
      {
          unsigned char needle[2] = {0xFF, 0XD9};
          char * c;
          c = memmem(b, len, needle, sizeof(needle));
          return c;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-11-05
        • 2014-02-09
        • 1970-01-01
        • 2022-11-25
        • 1970-01-01
        • 2016-07-25
        • 2011-08-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多