2011-05-22 39 views
1

我已经使用fread将文件读入到一个字符数组中。现在我想要搜索该数组中的两个连续的十六进制值,即FF后跟D9(它是一个jpeg标记,表示文件的结尾)。下面是我用做代码:在文件的字符数组中搜索2个连续的十六进制值

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循环,当我执行程序时,会遍历数组中的所有字符,并且不会停止,直到出现界限错误。我很难过,请帮忙。

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

在此先感谢。

+0

我其实不相信你的条件是正确的。不应该是'!(* p1 ==(unsigned char)0xFF && * p2 ==(unsigned char)0xD9)'而不是? (暂且不谈,你用'unsigned char'和'unsigned int'的问题)就像目前所写的,似乎只要遇到0xFF *或* 0xD9就会结束循环。 – 2011-05-22 18:18:54

+0

为什么不使用['strstr()'](http://www.cplusplus.com/reference/clibrary/cstring/strstr/)? – Joulukuusi 2011-05-22 18:27:07

+0

将'&&'更改为'||'并阅读Oli的答案。 – 2011-05-22 18:27:22

回答

1

你正在犯规整数提升!=(以及类似的)的两个操作数都被提升为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,并避免所有的铸件。

[注意,在这一切之上,你的循环逻辑是不正确,在各种评论中指出。]

+0

谢谢你花时间解释这个:) – Chris 2011-05-22 19:08:32

1

4E将自己提升到一个正整数,但*p1将与FF负,然后将被提升为非常大的无符号值,这将远远大于FF。

你需要让p1签名。

1

您可以编写代码短了很多如:

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

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

2

为什么不使用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; 
} 
+0

如果'memchr'返回0(它随后开始从'(unsigned char *)0 + 1'开始搜索),那么你的代码有一个主要的错误。当然,在这种情况下,OP的代码也被破坏了(通过设计)。 – 2011-05-22 18:43:35

+0

此外,虽然在实践中它应该工作,但我认为将'UINT_MAX'传递给'memchr'就像这样的“未知大小”实际上导致了UB。根据标准,'memchr'的buffer参数实际上必须是指定大小的对象。 – 2011-05-22 18:44:52

+0

@R .:在关于未知缓冲区大小的评论中指出。我将发布一个需要大小参数的版本。 – 2011-05-22 18:45:37

0

用void *将memmem(常量无效*草垛,为size_t haystacklen,常量无效*针,为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; 
} 
相关问题