views:

411

answers:

8

Is the following code 100% portable?

int a=10;
size_t size_of_int = (char *)(&a+1)-(char*)(&a); // No problem here?

std::cout<<size_of_int;// or printf("%zu",size_of_int);

P.S: The question is only for learning purpose. So please don't give answers like Use sizeof() etc

+1  A: 

Why not just:

size_t size_of_int = sizeof(int);
Paul Betts
That does not answer my question. I know we have the `sizeof()` operator for such purpose. The question is just for learning purpose. :)
Prasoon Saurav
+5  A: 
Kirill V. Lyadvinsky
wilx
FredOverflow
A: 

The code above will portably compute sizeof(int) on a target platform but the latter is implementation defined - you will get different results on different platforms.

sharptooth
A: 

Yes, it gives you the equivalent of sizeof(a) but using ptrdiff_t instead of size_t type.

wilx
A: 

There was a debate on a similar question.

See the comments on my answer to that question for some pointers at why this is not only non-portable, but also is undefined behaviour by the standard.

Frank Bollack
+13  A: 

From ANSI-ISO-IEC 14882-2003, p.87 (c++03):

"75) Another way to approach pointer arithmetic is first to convert the pointer(s) to character pointer(s): In this scheme the integral value of the expression added to or subtracted from the converted pointer is first multiplied by the size of the object originally pointed to, and the resulting pointer is converted back to the original type. For pointer subtraction, the result of the difference between the character pointers is similarly divided by the size of the object originally pointed to."

This seems to suggest that the pointer difference equals to the object size.

If we remove the UB'ness from incrementing a pointer to a scalar a and turn a into an array:

int a[1];
size_t size_of_int = (char*)(a+1) - (char*)(a);

std::cout<<size_of_int;// or printf("%zu",size_of_int);

Then this looks OK. The clauses about alignment requirements are consistent with the footnote, if alignment requirements are always divisible by the size of the object.

UPDATE: Interesting. As most of you probably know, GCC allows to specify an explicit alignment to types as an extension. But I can't break OP's "sizeof" method with it because GCC refuses to compile it:

#include <stdio.h>

typedef int a8_int __attribute__((aligned(8)));

int main()
{
 a8_int v[2];

 printf("=>%d\n",((char*)&v[1]-(char*)&v[0]));
}

The message is error: alignment of array elements is greater than element size.

Luther Blissett
If you replace `-)
FredOverflow
@Fred: Thank you!
Luther Blissett
Prasoon Saurav
@Prasoon: Yes, but C++ is not C99, and I prefer a solution that works in both languages.
FredOverflow
is `sizeof(char)==1` guaranteed by the standard ? if not, then this might not be 100% portable.
smerlin
@smerlin: `is sizeof(char)==1 guaranteed by the standard ?` Yes.
Prasoon Saurav
5.3.3-1 [expr.sizeof] : "sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1;".
Luther Blissett
+2  A: 

No. This code won't work as you expect on every plattform. At least in theory, there might be a plattform with e.g. 24 bit integers (=3 bytes) but 32 bit alignment. Such alignments are not untypical for (older or simpler) plattforms. Then, your code would return 4, but sizeof( int ) would return 3.

But I am not aware of a real hardware that behaves that way. In practice, your code will work on most or all plattforms.

Tobias Haustein
-1, on such platforms `sizeof(int)` is 4. However, 8 of those 32 bits will not take part in the value representation of the int. Only for (unsigned) char do you get the guarantee that all bits participate in the value representation. (Has to, else you couldn't memcpy things).
MSalters
+2  A: 

It's not 100% portable for the following reasons:

  1. Edit: You'd best use int a[1]; and then a+1 becomes definitively valid.
  2. &a invokes undefined behaviour on objects of register storage class.
  3. In case of alignment restrictions that are larger or equal than the size of int type, size_of_int will not contain the correct answer.

Disclaimer:

I am uncertain if the above hold for C++.

Michael Foukarakis
Drew Hall
It's never UB. In C it's ill-formed (diagnostic required) and in C++ it's allowed (sicne compilers ignored it anyway).
MSalters
@MSalters: I assume you were talking about (1)? It, in fact, - after actually referring to the standard - according to the semantics for additive operators is indeed OK. I cannot find where it's considered as ill-formed. Can you help?
Michael Foukarakis
@mfukar: sorry, I responded to Drew Hall's comment, which commented on the UB assumed in (2).
MSalters