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 个字节。
没有。 memchr
只能搜索由 unsigned char
.
表示的值
如果您提供 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 表达式:v
和 r[n]
是 ℕ(带零)的元素,而不是精度有限的机器数。 C 符号用于相等、base-2 左移和按位或,但这些也意味着 ℕ 中的数学运算符。 (如果该站点启用了 MathJax,我会使用正确的数学符号。)
对于有符号整数类型,方程式将包括处理负数的规则,对于浮点数,它们会将字节拆分为符号、指数和尾数位域,然后将它们重新组合成 ℚ 的元素。
您展示的示例代码,
const int arr[5] = {0x1021, 0x8988, 0x706, 0x50, 0x22};
int *ptr = memchr(arr, 0x89, sizeof(arr));
是,假设 int
和 int32_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
我想现在答案已经很明显了。
我对 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 个字节。
没有。
表示的值memchr
只能搜索由unsigned char
.如果您提供
的 对象表示 中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 表达式:
v
和r[n]
是 ℕ(带零)的元素,而不是精度有限的机器数。 C 符号用于相等、base-2 左移和按位或,但这些也意味着 ℕ 中的数学运算符。 (如果该站点启用了 MathJax,我会使用正确的数学符号。)对于有符号整数类型,方程式将包括处理负数的规则,对于浮点数,它们会将字节拆分为符号、指数和尾数位域,然后将它们重新组合成 ℚ 的元素。
- 大端:
您展示的示例代码,
const int arr[5] = {0x1021, 0x8988, 0x706, 0x50, 0x22};
int *ptr = memchr(arr, 0x89, sizeof(arr));
是,假设 int
和 int32_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
我想现在答案已经很明显了。