Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternate way of computing size of a type using pointer arithmetic

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

like image 822
Prasoon Saurav Avatar asked Aug 02 '10 10:08

Prasoon Saurav


2 Answers

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.

like image 165
Nordic Mainframe Avatar answered Oct 10 '22 11:10

Nordic Mainframe


&a+1 will lead to undefined behavior according to the C++ Standard 5.7/5:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. <...> If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

&a+1 is OK according to 5.7/4:

For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

That means that 5.7/5 can be applied without UB. And finally remark 75 from 5.7/6 as @Luther Blissett noted in his answer says that the code in the question is valid.


In the production code you should use sizeof instead. But the C++ Standard doesn't guarantee that sizeof(int) will result in 4 on every 32-bit platform.

like image 4
Kirill V. Lyadvinsky Avatar answered Oct 10 '22 11:10

Kirill V. Lyadvinsky