C memcmp 函数
最后修改:2025 年 4 月 8 日
内存比较是 C 编程的基础,而 memcmp
是用于比较内存位置之间数据的关键函数。本教程将深入介绍 memcmp
,包括其语法、用法和潜在的陷阱。我们将探讨实际示例,并讨论对关键应用程序更安全的选择。理解 memcmp
有助于优化内存操作,同时保持程序的安全性和可靠性。
什么是 memcmp?
memcmp
函数逐字节比较两个内存块。它声明在 string.h
中,并接受三个参数:指向两个内存块的指针和要比较的字节数。如果内存块相同,memcmp
返回零;如果第一个不同字节在第一个块中较低,则返回负数;如果较高,则返回正数。与字符串比较函数不同,memcmp
比较所有字节,包括空字节。
memcmp 的基本用法
此示例演示了如何使用 memcmp
比较两个数组。
#include <stdio.h> #include <string.h> int main() { char arr1[] = {1, 2, 3, 4, 5}; char arr2[] = {1, 2, 3, 4, 5}; char arr3[] = {1, 2, 3, 4, 6}; int result1 = memcmp(arr1, arr2, sizeof(arr1)); int result2 = memcmp(arr1, arr3, sizeof(arr1)); printf("Comparison 1: %d\n", result1); printf("Comparison 2: %d\n", result2); return 0; }
在这里,memcmp
逐字节比较两个数组。第一次比较返回 0,表示内容相同。第二次返回负值,因为 arr1
中的第五个字节 (5) 小于 arr3
中的第五个字节 (6)。比较是基于原始字节进行的,而不是解释后的值。请务必确保大小参数与您预期的比较长度相符。
使用 memcmp 比较字符串
memcmp
可以比较字符串,但与 strcmp
不同,如下例所示。
#include <stdio.h> #include <string.h> int main() { char str1[] = "apple"; char str2[] = "apples"; char str3[] = "apple\0extra"; printf("strcmp(str1, str2): %d\n", strcmp(str1, str2)); printf("memcmp(str1, str2, 5): %d\n", memcmp(str1, str2, 5)); printf("memcmp(str1, str3, 6): %d\n", memcmp(str1, str3, 6)); return 0; }
此示例显示了 strcmp
和 memcmp
之间的主要区别。虽然 strcmp
在遇到空终止符时停止,但 memcmp
会比较所有指定的字节。第一次 memcmp
只比较 5 个字节并发现相等。第二次则会比较到空字节。当比较二进制数据或需要将空字节包含在比较中时,memcmp
非常有用。
使用 memcmp 比较结构
此示例演示了如何使用 memcmp
比较结构。
#include <stdio.h> #include <string.h> typedef struct { int id; char name[20]; float score; } Student; int main() { Student s1 = {101, "Alice", 95.5}; Student s2 = {101, "Alice", 95.5}; Student s3 = {102, "Bob", 88.0}; int result1 = memcmp(&s1, &s2, sizeof(Student)); int result2 = memcmp(&s1, &s3, sizeof(Student)); printf("Comparison 1: %d\n", result1); printf("Comparison 2: %d\n", result2); return 0; }
在这里,memcmp
逐字节比较整个结构。第一次比较返回 0,因为结构相同。第二次返回非零值,因为它们不同。请注意,填充字节可能会影响比较结果。此方法速度很快,但由于潜在的位级差异,对于包含指针或浮点数的结构可能无法可靠工作。
更安全的替代方案:memcmp_s
此示例演示了 C11 中提供的更安全的 memcmp_s
函数。
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> #include <string.h> int main() { char data1[5] = {1, 2, 3, 4, 5}; char data2[10] = {1, 2, 3, 4, 5}; int result; errno_t err = memcmp_s(data1, sizeof(data1), data2, sizeof(data2), sizeof(data1), &result); if (err != 0) { printf("Error: Invalid parameters or size mismatch\n"); return 1; } printf("Comparison result: %d\n", result); return 0; }
memcmp_s
增加了边界检查,并在参数无效时返回错误。它会检查比较大小是否超过任一缓冲区。函数在成功时返回零,在失败时返回非零。虽然它并非普遍可用,但对于面向 C11 或更高版本且支持边界检查的安全关键代码,建议使用它。
宏 __STDC_WANT_LIB_EXT1__
定义为 1,明确表示程序希望使用 C11 标准库的可选扩展。没有这个宏,某些更安全的功能,包括 memcmp_s
,可能不会由编译器提供。此功能允许开发人员选择性地启用附加功能,以提高其程序的安全性和可靠性。
比较部分数组
此示例展示了如何使用 memcmp
比较数组的各个部分。
#include <stdio.h> #include <string.h> int main() { int arr1[] = {1, 2, 3, 4, 5, 6, 7, 8}; int arr2[] = {9, 10, 3, 4, 5, 6, 11, 12}; // Compare middle 4 elements (3,4,5,6) int result = memcmp(arr1 + 2, arr2 + 2, 4 * sizeof(int)); if (result == 0) { printf("Middle elements are identical\n"); } else { printf("Middle elements differ\n"); } return 0; }
在这里,memcmp
比较从每个数组的第三个元素开始的四个整数。大小计算为 4 * sizeof(int)
以获得正确的字节数。此技术对于比较数组或缓冲区的特定部分很有用。由于两个数组中的中间元素相同,因此比较返回 0。
使用 memcmp 的最佳实践
- 检查缓冲区大小:确保两个缓冲区都足够大以进行比较。
- 理解字节序:结果在不同的字节序系统上可能会有所不同。
- 考虑更安全的替代方案:在可用时,在安全关键代码中使用
memcmp_s
。 - 验证指针有效性:在比较之前,请确保两个指针都有效。
- 使用正确的尺寸计算:请记住,尺寸参数的单位是字节。
来源
本教程介绍了 memcmp
函数,从基本用法到高级注意事项。虽然它功能强大,但请始终小心使用内存操作,以防止程序中的安全漏洞和未定义行为。
作者
列表 C 标准库。