首页 文章

C:两个void指针的区别是什么类型?

提问于
浏览
2

如果我减去两个void指针,我得到指针位置之间的相对距离(至少在我的测试系统上) . 我应该使用什么类型来存储结果,以便它与64位系统兼容? size_t是正确的类型还是长?

背景:我们需要检查给定的void指针是否可以安全地用作双指针 . 我们曾经将指针强制转换为int并检查低三位是否为零,但是我们当前的编码标准不再允许将指针转换为整数类型 . 我正在考虑计算void指针和NULL指针之间的差异,并检查该差异是否可以被8分割 . 假设NULL指针始终是8字节对齐的?

4 回答

  • 4

    在C标准中没有定义void指针的减法 . 指针的减法仅在它们都指向同一个数组并且void指针不能指向任何数组时定义,因为您不能拥有带有void元素的数组 .

    很可能你正在使用gcc或者兼容的东西,它允许对void指针进行算术运算,作为它被视为char指针的扩展 . 但是严格的C编译器不应该允许对void指针进行指针运算 .

  • 2

    来自 C11, 6.5.6 Additive operators /9 (我的斜体):

    当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异 . 结果的大小是实现定义的,其类型(有符号整数类型)是在<stddef.h>头中定义的ptrdiff_t .

    通过该部分,从指针中减去NULL也是技术上未定义的行为,因为 NULL 绝不能被视为指向同一数组元素的指针,或者超出它的指针 . 指针减法实际上仅限于获取同一数组中两个元素之间的索引差异 .

    所以你可能想重新考虑你正在进行的这种检查,特别是考虑到double实际上不需要长度为8个字节的事实,即使它是,标准中也没有要求它对齐一个八字节的边界 .

    我更倾向于在你的函数的文档中说明传递的值需要是一个有效的 double 指针,如果你的函数的用户违反了该 Contract ,那么所有的赌注都将被取消 .

  • 4

    如果我减去两个void指针,我得到指针位置之间的相对距离(以字节为单位)(至少在我的测试系统上) .

    有一个严格的规则来减去两个指针 . C11-§6.5.6:

    当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异 . [...]


    两个void指针的区别是什么类型?

    它应该是 ptrdiff_t .

    [...]结果的大小是实现定义的,其类型(有符号整数类型)是在<stddef.h>头中定义的ptrdiff_t . [...]

  • 5

    问题摘要:

    • 您将空指针常量宏NULL与空指针混淆 . 这是两个不同的术语 . NULL宏始终等于0,但空指针可以具有任何值 . See this .

    • 话虽如此,使用空指针和NULL宏进行指针运算没有任何意义 . 这样做会调用未定义的行为,因为指针必须指向同一个数组 . 请参阅paxdiablo的回答 .

    • 此外,如Art的答案所述,您无法对void指针进行任何形式的算术运算 . 和 - 运算符指定为(6.5.6):

    另外,两个操作数都应具有算术类型,或者一个操作数应是指向完整对象类型的指针,另一个操作数应具有整数类型 .

    void指针是指向不完整类型的指针,因此如果其中一个或两个操作数都是void指针,则代码无效C.

    注意,GCC有一个非标准的扩展,它允许void指针算术,通过将void指针视为这种情况下的指针到字节 . 如果您打算编写安全且可移植的程序,切勿使用此非标准功能 . 如果希望GCC表现为标准C编译器(符合实现),请使用 gcc -std=c11 -pedantic-errors 进行编译 .

相关问题