在C11中是否有定义的方法进行指针减法? [英] Is there a defined way to do pointer subtraction in C11?

查看:126
本文介绍了在C11中是否有定义的方法进行指针减法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以在C11中从另一个指针中减去一个指针,并始终定义结果?

标准说,如果结果无法表示为ptrdiff_t类型,则行为是不确定的.

我对依赖静态断言的解决方案持开放态度,这些静态断言可望在现代通用32或64位环境中传递合理的实现.我想避免依赖任何类型的运行时检查的解决方案.

如果指向类型的大小大于1,我可以静态断言size_t和ptrdiff_t以具有相同数量的非填充位.这种部分解决方案取决于我不确定的两件事,因此对此的任何反馈都将提供部分答案:

  1. 可以预期,在现代通用32或64位环境中的合理实现中,ptrdiff_t的值位最多比size_t小.

  2. 我对标准的理解是正确的,因为定义了两个指向大小大于1的对象的指针之间的差异,即使将指针转换为字符指针也无法定义相同的差异.这种理解似乎与委员会草案中的脚注106不一致,但是据我了解,脚注不是规范性的.

解决方案

根据标准

仅当两个指针都指向同一对象(包括一端过去"的指针)时,才可以减去指针.

减去uintptr_tintptr_t不一定有意义,因为同样,根据标准,没有特别的方法必须定义从指针到整数的转换.特别是

  • 考虑分段内存模型中的远指针,在该模型中,可能存在不止一种表示给定地址的方式(例如,在x86上为段+偏移量).

  • 考虑具有处理器忽略的位的指针. (例如,Motorola 68000处理器,它具有32位指针,但前8位被忽略.)

因此,不幸的是,根据标准,没有办法便携地执行此操作.

记住:size_t是对象的最大大小.它不是地址空间的大小. size_t的范围小于uintptr_t和朋友的范围是完全合法的.与ptrdiff_t相同:ptrdiff_t的范围小于uintptr_t是完全合法的.例如,想象一下一个分段内存模型,其中您不能分配大于段的任何内容,在这种情况下,size_tptrdiff_t可能能够表示段的大小,但不能表示地址空间的大小. /p>

根据实践

在您使用的计算机(现代32位和64位计算机)上,uintptr_t仅包含指针地址.减去.这是实现定义的行为,但不是未定义的行为.

请勿在不进行强制转换的情况下减去原始指针,除非它们指向同一对象或该对象之后的地址.使用指针算术时,编译器可以并且会做出别名假设.不仅程序在技术上是错误的,而且编译器在此处生成不良代码的历史由来已久.

现在有一个争论,确切地说,这意味着一个指向同一对象的指针,但是我上次检查时这个争论仍未解决.

Is there a way to subtract one pointer from another in C11 and have the result be always defined?

The standard says the behavior is undefined if the result is not representable as type ptrdiff_t.

I am open to a solution relying on static assertions that are expected to pass on a reasonable implementation in a modern general purpose 32 or 64 bit environment. I would like to avoid solutions that rely on any sort of runtime checks.

If the pointed to type has size greater than 1, I can static assert size_t and ptrdiff_t to have the same number of nonpadding bits. This partial solution relies on two things I am not sure about, so any feedback on this would provide a partial answer:

  1. It can be expected that ptrdiff_t has at most one fewer value bit than size_t in a reasonable implementation in a modern general purpose 32 or 64 bit environment.

  2. I am correct in my understanding of the standard, in that the difference between two pointers to objects of size greater than 1 is defined, even when the same difference would be undefined if the pointers were cast to character pointers. This understanding seems inconsistent with footnote 106 in the committee draft, but it is my understanding that footnotes are not normative.

解决方案

According to the Standard

You can only subtract pointers if both pointers point to the same object, which includes the "one-past-the-end" pointer.

Subtracting uintptr_t or intptr_t is not necessarily meaningful, because, again, according to the standard, there is no particular way that the conversion from pointer to integer has to be defined. In particular,

  • Consider far pointers in a segmented memory model, where there may be more than one way to represent a given address (segment + offset, for example, on x86).

  • Consider pointers with bits that are ignored by processor. (For example, the Motorola 68000 processor, which has 32-bit pointers but the top 8 bits are ignored.)

So, unfortunately, there is no way to do this portably, according to the standard.

Remember: size_t is the maximum size of an object. It is not the size of your address space. It is entirely legal for size_t to have less range that uintptr_t and friends. Same with ptrdiff_t: it is entirely legal for ptrdiff_t to have less range than uintptr_t. Imagine, for example, a segmented memory model where you cannot allocate anything larger than a segment, in this case, size_t and ptrdiff_t might be able to represent the size of a segment but not the size of your address space.

According to Practice

On the computers which you use (modern 32-bit and 64-bit computers), a uintptr_t will just contain the pointer address. Subtract away. This is implementation-defined but not undefined behavior.

Do not subtract the original pointers without casting unless they point to the same object, or to the address past that object. Compilers can and will make aliasing assumptions when you use pointer arithmetic. Not only is your program "technically" wrong, but there is a long history of compilers producing bad code here.

There is a bit of an argument going on right now about what, exactly, it means for a pointer to point to the same object, but this argument was unresolved last time I checked.

这篇关于在C11中是否有定义的方法进行指针减法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆