有没有办法在C11中从另一个指针中减去一个指针,并且总是定义结果?
标准表示如果结果不能表示为ptrdiff_t类型,则行为是未定义的。
我愿意依赖于静态断言的解决方案,这些断言有望在现代通用32或64位环境中传递合理的实现。我想避免依赖任何运行时检查的解决方案。
如果指向的类型的大小大于1,我可以静态断言size_t和ptrdiff_t具有相同数量的非填充位。这个部分解决方案依赖于我不确定的两件事,所以对此的任何反馈都会提供部分答案:
在现代通用32或64位环境的合理实现中,可以预期ptrdiff_t的值位最多比size_t少一个。
我对标准的理解是正确的,因为定义了两个指向大小大于1的对象的指针之间的差异,即使指针被强制转换为字符指针时也会定义相同的差异。这种理解似乎与委员会草案中的脚注106不一致,但我的理解是脚注不是规范性的。
答案 0 :(得分:5)
如果两个指针都指向同一个对象,那么你只能减去指针,其中包括“一个接一个”的指针。
减去uintptr_t
或intptr_t
并不一定有意义,因为同样,根据标准,没有必要定义从指针到整数的转换的特定方式。特别是,
考虑分段内存模型中的远指针,其中可能有多种方式表示给定地址(段+偏移,例如,在x86上)。
考虑具有被处理器忽略的位的指针。 (例如,Motorola 68000处理器,它具有32位指针,但前8位被忽略。)
所以,不幸的是,根据标准,没有办法做到这一点。
请记住: size_t
是对象的最大大小。 不地址空间的大小。 size_t
uintptr_t
和朋友的范围较小是完全合法的。与ptrdiff_t
相同:ptrdiff_t
的范围小于uintptr_t
是完全合法的。想象一下,例如,一个分段内存模型,你不能分配任何大于一个段的东西,在这种情况下,size_t
和ptrdiff_t
可能能够代表一个段的大小,但不能代表你的大小地址空间。
在您使用的计算机(现代32位和64位计算机)上,uintptr_t
将只包含指针地址。减去。这是实现定义但未定义的行为。
除非指向同一个对象或指向该对象之后的地址,否则不要在不进行强制转换的情况下减去原始指针。当您使用指针算法时,编译器可以并且将会做出别名假设。您的程序不仅“技术上”错误,而且编译器在这里产生错误代码的历史很长。
现在有一个争论正在进行,关于指向同一个对象的指针究竟是什么意思,但是这个参数在我上次检查时没有得到解决。