21

Does the C99/C++11 standard guarantee that sizeof(size_t) == sizeof(void*) is always true?

size_t f(void* p)
{
    return (size_t)(p); // Is it safe?
}

void* f(size_t n)
{
    return (void*)(n); // Is it safe?
}
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 8
    I don't understand why it is being voted for close. It is a legitimate question. – Nawaz Sep 15 '13 at 09:23
  • 5
    @Nawaz +1. I guess ever since "demonstrate minimal knowledge" became a closing reason, some people feel the need to apply it a little too broadly. – Angew is no longer proud of SO Sep 15 '13 at 09:26
  • 1
    `size_t` and `void*` are two irrelevant types. Why they should be equal at all? I understand `size_t` tries to store largest number and `void*` as a pointer tries to access largest memory address space. But it doesn't say they must be equal. – masoud Sep 15 '13 at 10:03
  • Related: _[`size_t` vs. `intptr_t`](http://stackoverflow.com/q/1464174/952747)_ – masoud Sep 22 '13 at 11:00
  • 1
    @deepmax: More precisely, `size_t` is the largest contiguous number of bytes addressable (the maximum length of an array). This can be well below the entire address space if you're using segmented memory or if you are using something like x86-64 (64-bit pointers; only 48-bits of which are usable, with a [giant hole](https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/AMD64-canonical--48-bit.svg/225px-AMD64-canonical--48-bit.svg.png) in the middle of the address space). – Andon M. Coleman Aug 30 '15 at 23:37

1 Answers1

14

No, that is not guaranteed. Use intptr_t or uintptr_t to safely store a pointer in an integer.

There are/were architectures where it makes sense for that to be false, such as the segmented DOS memory model. There the memory was structured in 64k segments - an object could never be larger than a segment, so 16-bit size_t would be enough. However, a pointer had "segment" and "offset" parts, so it would by definition have to be larger than 16 bits to be able to refer to different segments.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 2
    Unfortunately `intptr_t` and `uintptr_t` are optional types and there may exist architectures for which no integral type exists that is big enough to contain a `void` pointer. – Bryan Olivier Sep 15 '13 at 09:27
  • 1
    @BryanOlivier True indeed. However, if a platform does support a big enough integer, I would most definitely expect the std. library to expost it by these typedefs. And if the platform does not, `size_t` wouldn't help either. So I'd say presence of these types can be used as an indicator whether such a cast is even possible. – Angew is no longer proud of SO Sep 15 '13 at 09:34
  • Isn't size_t supposed to by the size of a pointer on most modern day operating systems ? – Vivek S Sep 15 '13 at 09:38
  • 2
    @VivekS Nope, `size_t` is really for object sizes. Most modern compilers will support `intptr_t` and `uintptr_t`, because otherwise the `%p` format specifier can not be implemented in C. – Bryan Olivier Sep 15 '13 at 09:44
  • 3
    @VivekS `size_t` is defined as an unsigned integral type capable of storing the size of the largest object that can (theoretically) be created by the program. – Angew is no longer proud of SO Sep 15 '13 at 09:45
  • @BryanOlivier Just curious, why couldn't `%p` be implemented simply by accessing the pointer value in chunks of largest-integer-size? – Angew is no longer proud of SO Sep 15 '13 at 10:22
  • @Angew How would you get those chunks from the pointer without first converting it into an integer, potentially losing some of the bits you'd select? AFAIK you can't bit-shift pointers in C. Of course, in assembler and friends, you can do the moral equivalent just fine - hence the "in C" qualifier. –  Sep 15 '13 at 10:32
  • @delnan Couldn't you do a `*(char*)&ptr` and then `*(((char*)&ptr) + 1)`... `*(((char*)&ptr) + (sizeof(void*) - 1))`? (where ptr is your pointer) – xanatos Sep 15 '13 at 10:41
  • 1
    @delnan How about `memcpy()`? Remember, we're talking compiler/library implementation, they *know* the bit pattern of the pointer in memory. [See example](http://ideone.com/1Z1dk0). – Angew is no longer proud of SO Sep 15 '13 at 10:45
  • @Angew Seems to work, I was constrained to thinking in 100% portable standard C. –  Sep 15 '13 at 10:52
  • @delnan Still possible. If I had used `unsigned char[sizeof(void*)]`, it would have actually been 100% portable standard C (based on C11[N1570], 6.2.6.1/4). – Angew is no longer proud of SO Sep 15 '13 at 11:01
  • @Angew Agreed, that would be possible. Of course endianness may make the printed value unintuitive. It may also print bits that are unused in the pointer, but all in all it should work. – Bryan Olivier Sep 15 '13 at 11:15
  • @BryanOlivier Yup; but as it's the compiler+library writer doing this, they know the endianness etc. – Angew is no longer proud of SO Sep 15 '13 at 11:30