Is there a defined way to do pointer subtraction in C11?

拈花ヽ惹草 提交于 2019-12-08 05:45:17

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/38442017/is-there-a-defined-way-to-do-pointer-subtraction-in-c11

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!