【问题标题】:How memchr in C actually works?C中的memchr实际上是如何工作的?
【发布时间】:2021-12-09 08:41:07
【问题描述】:

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

我有两个问题:

1.如果它将任何内容转换为unsigned char,那么它如何比较大小大于unsigned char 的数字,例如int 类型。 2.如果是逐字节比较返回然后返回字符第一次出现的地址,那么假设我要在数组中搜索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;
}

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

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

【问题讨论】:

  • 一般来说,尝试在任何其他类型的数组上使用memchr 是不可移植的。

标签: arrays c pointers memory string.h


【解决方案1】:
  1. 它没有。 memchr 只能搜索由unsigned char 表示的值。

  2. 如果您将ints 的数组作为memchr 的第一个参数提供,那么它将在对象表示中查找您作为第二个参数提供的unsigned char 值每个int

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

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

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

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

您展示的示例代码,

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

是,假设intint32_t是同一个类型,并且假设是little-endian对象表示,我们不关心负数是如何表示的,因为数组中的所有数字都是正数,相当于

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 返回的指针不一定是指向int 的有效指针(也不是除unsigned char 之外的任何其他指针)。 )

【讨论】:

    【解决方案2】:

    只需添加几行代码,您就可以自己轻松找到答案,而不是问这个问题。如果你真的想学习编程,你需要自己做。

    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
    

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

    【讨论】:

      猜你喜欢
      • 2021-01-21
      • 2011-09-27
      • 2021-12-16
      • 2013-03-14
      • 2021-03-23
      • 2011-02-11
      • 2017-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多