C 中的 memchr 实际上是如何工作的?

How memchr in C actually works?

我对 memchr()C 中的工作技术有点困惑。我观察了 memchr() 的不同实现,发现它首先将字符或数字转换为 unsigned char 类型,然后逐字节搜索数组。

我有两个问题:

1.If 它将任何东西转换为 unsigned char 然后它如何比较大小大于 unsigned char 的数字,例如 int 类型。 2.If 它逐字节比较,然后 returns 然后 returns 字符第一次出现的地址,然后假设我想在数组中搜索 0x8

#include <stdio.h>
#include <string.h>

int main(void)
{
  const int arr[5] = {0x1021, 0x8988, 0x706, 0x50, 0x22};
  int * ptr;

  ptr = memchr(arr, 0x89, sizeof(arr));
  printf("arr:%p ptr:%p\n", arr, ptr);

  return 0;
}

它应该 return 数组的第 3 个字节的地址,因为 0x89 与数组的第 7 个字节的元素 0x8988 的第一个字节匹配 memchr() 逐字节匹配 (unsigned char) 而不是 int 类型。

假设:int 是 4 个字节,unsigned char 是 1 个字节。

  1. 没有。 memchr 只能搜索由 unsigned char.

    表示的值
  2. 如果您提供 int 的数组作为 memchr 的第一个参数,那么它会寻找您提供的 unsigned char 值作为第二个参数,在每个 int.

    对象表示

    除了unsigned char之外的任意类型T的对象表示,就是union { T v; unsigned char r[sizeof(T)]; }的两个成员的对应关系。对象表示是实现定义的。例如,四字节 unsigned int 的两个最常见的对象表示是

    • 大端:v == (r[0] << 24 | r[1] << 16 | r[2] << 8 | r[3])
    • 小端:v == (r[3] << 24 | r[2] << 16 | r[1] << 8 | r[0])

    这些应该被理解为数学方程式,而不是 C 表达式:vr[n] 是 ℕ(带零)的元素,而不是精度有限的机器数。 C 符号用于相等、base-2 左移和按位或,但这些也意味着 ℕ 中的数学运算符。 (如果该站点启用了 MathJax,我会使用正确的数学符号。)

    对于有符号整数类型,方程式将包括处理负数的规则,对于浮点数,它们会将字节拆分为符号、指数和尾数位域,然后将它们重新组合成 ℚ 的元素。

您展示的示例代码,

const int arr[5] = {0x1021, 0x8988, 0x706, 0x50, 0x22};
int *ptr = memchr(arr, 0x89, sizeof(arr));

是,假设 intint32_t 是相同的类型,并假设小端对象表示,我们不关心负数是如何表示的,因为数组中的所有数字为正数,相当于

const uint8_t arr[20] = {
  0x21, 0x10, 0x00, 0x00,
  0x88, 0x89, 0x00, 0x00,
  0x06, 0x07, 0x00, 0x00,
  0x50, 0x00, 0x00, 0x00,
  0x22, 0x00, 0x00, 0x00,
};
int *ptr = memchr(arr, 0x89, sizeof(arr));

您可以看到正在搜索的值 0x89 出现在距第二个数组开头的偏移量 5 处。

(注意:ptr的类型应该是uint8_t *,而不是int *memchr返回的指针不一定是指向[=14的有效指针=](除了 unsigned char 之外的任何其他内容)。)

不用问这个问题,您只需添加几行代码就可以轻松地自己找到答案。真想学编程就得自己动手了。

int main(void)
{
  const int arr[5] = {0x1021, 0x8988, 0x706, 0x50, 0x22};
  int * ptr;
  unsigned char *ucp = arr;

  for(size_t i = 0; i < sizeof(arr); i++)
  {
      printf("Byte no: %02zu = 0x%02hhx, %s\n", i, ucp[i], ucp[i] == 0x89 ? " <<<----" : "");
  }
  
  ptr = memchr(arr, 0x89, sizeof(arr));
  printf("arr:%p ptr:%p diff = %zd\n", (void *)arr, (void *)ptr, (ptrdiff_t)ptr - (ptrdiff_t)arr);
}

和输出:

Byte no: 00 = 0x21, 
Byte no: 01 = 0x10, 
Byte no: 02 = 0x00, 
Byte no: 03 = 0x00, 
Byte no: 04 = 0x88, 
Byte no: 05 = 0x89,  <<<----
Byte no: 06 = 0x00, 
Byte no: 07 = 0x00, 
Byte no: 08 = 0x06, 
Byte no: 09 = 0x07, 
Byte no: 10 = 0x00, 
Byte no: 11 = 0x00, 
Byte no: 12 = 0x50, 
Byte no: 13 = 0x00, 
Byte no: 14 = 0x00, 
Byte no: 15 = 0x00, 
Byte no: 16 = 0x22, 
Byte no: 17 = 0x00, 
Byte no: 18 = 0x00, 
Byte no: 19 = 0x00, 
arr:0x7fffc2747900 ptr:0x7fffc2747905 diff = 5

我想现在答案已经很明显了。