在 C11 中是否有定义的指针减法方法?
Is there a defined way to do pointer subtraction in C11?
有没有办法在 C11 中用一个指针减去另一个指针并始终定义结果?
标准表示,如果结果不能表示为 ptrdiff_t 类型,则行为未定义。
我对依赖静态断言的解决方案持开放态度,该解决方案有望在现代通用 32 位或 64 位环境中传递合理的实现。我想避免依赖任何类型的运行时检查的解决方案。
如果指向的类型的大小大于 1,我可以静态断言 size_t 和 ptrdiff_t 具有相同数量的非填充位。这个部分解决方案依赖于我不确定的两件事,因此对此的任何反馈都会提供部分答案:
在现代通用 32 位或 64 位环境中的合理实现中,可以预期 ptrdiff_t 最多比 size_t 少一个值位。
我对标准的理解是正确的,因为定义了两个指向大小大于 1 的对象的指针之间的差异,即使如果指针被强制转换,相同的差异将是未定义的到字符指针。这种理解似乎与委员会草案中的脚注106不一致,但我的理解是脚注不规范。
根据标准
只有当两个指针都指向同一个对象时才能减去指针,其中包括 "one-past-the-end" 指针。
减去 uintptr_t
或 intptr_t
不一定有意义,因为,同样,根据标准,没有特定的方法来定义从指针到整数的转换。特别是,
考虑分段内存模型中的远指针,其中可能有不止一种方式来表示给定地址(段 + 偏移量,例如,在 x86 上)。
考虑带有被处理器忽略的位的指针。 (例如,Motorola 68000 处理器,它有 32 位指针,但高 8 位被忽略。)
因此,很遗憾,根据标准,没有办法以可移植的方式执行此操作。
记住: size_t
是对象的最大尺寸。它不是您地址的大小space。 size_t
的范围小于 uintptr_t
和朋友的范围是完全合法的。与 ptrdiff_t
相同:ptrdiff_t
的范围小于 uintptr_t
是完全合法的。想象一下,例如,一个分段内存模型,您不能分配任何大于段的东西,在这种情况下,size_t
和 ptrdiff_t
可能能够表示段的大小,但不能表示您的段的大小地址 space.
根据惯例
在您使用的计算机(现代 32 位和 64 位计算机)上,uintptr_t
将只包含指针地址。减去。这是实现定义的但不是未定义的行为。
不要在没有转换的情况下减去原始指针,除非它们指向同一个对象,或者指向该对象之后的地址。当您使用指针算法时,编译器可以并且将会做出别名假设。不仅您的程序 "technically" 错误,而且编译器在这里产生错误代码的历史由来已久。
关于指向同一个对象的指针到底意味着什么,现在有一些争论,但我上次检查时这个争论还没有解决。
有没有办法在 C11 中用一个指针减去另一个指针并始终定义结果?
标准表示,如果结果不能表示为 ptrdiff_t 类型,则行为未定义。
我对依赖静态断言的解决方案持开放态度,该解决方案有望在现代通用 32 位或 64 位环境中传递合理的实现。我想避免依赖任何类型的运行时检查的解决方案。
如果指向的类型的大小大于 1,我可以静态断言 size_t 和 ptrdiff_t 具有相同数量的非填充位。这个部分解决方案依赖于我不确定的两件事,因此对此的任何反馈都会提供部分答案:
在现代通用 32 位或 64 位环境中的合理实现中,可以预期 ptrdiff_t 最多比 size_t 少一个值位。
我对标准的理解是正确的,因为定义了两个指向大小大于 1 的对象的指针之间的差异,即使如果指针被强制转换,相同的差异将是未定义的到字符指针。这种理解似乎与委员会草案中的脚注106不一致,但我的理解是脚注不规范。
根据标准
只有当两个指针都指向同一个对象时才能减去指针,其中包括 "one-past-the-end" 指针。
减去 uintptr_t
或 intptr_t
不一定有意义,因为,同样,根据标准,没有特定的方法来定义从指针到整数的转换。特别是,
考虑分段内存模型中的远指针,其中可能有不止一种方式来表示给定地址(段 + 偏移量,例如,在 x86 上)。
考虑带有被处理器忽略的位的指针。 (例如,Motorola 68000 处理器,它有 32 位指针,但高 8 位被忽略。)
因此,很遗憾,根据标准,没有办法以可移植的方式执行此操作。
记住: size_t
是对象的最大尺寸。它不是您地址的大小space。 size_t
的范围小于 uintptr_t
和朋友的范围是完全合法的。与 ptrdiff_t
相同:ptrdiff_t
的范围小于 uintptr_t
是完全合法的。想象一下,例如,一个分段内存模型,您不能分配任何大于段的东西,在这种情况下,size_t
和 ptrdiff_t
可能能够表示段的大小,但不能表示您的段的大小地址 space.
根据惯例
在您使用的计算机(现代 32 位和 64 位计算机)上,uintptr_t
将只包含指针地址。减去。这是实现定义的但不是未定义的行为。
不要在没有转换的情况下减去原始指针,除非它们指向同一个对象,或者指向该对象之后的地址。当您使用指针算法时,编译器可以并且将会做出别名假设。不仅您的程序 "technically" 错误,而且编译器在这里产生错误代码的历史由来已久。
关于指向同一个对象的指针到底意味着什么,现在有一些争论,但我上次检查时这个争论还没有解决。