sizeof

Hi,
how can I know the size of an int or double whithout using sizeof? It´s in the stroustrup´s book principles and practice using c++.
tks!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

int main()
{
    const int i = 0 ;

    const int* pi = &i ; // address of i
    const int* pi2 = pi+1 ; // address of a hypothetical int immediately after i in memory
    // "An object that is not an array element is considered to belong to a single-element array for this purpose"
    // http://eel.is/c++draft/expr.add#footnote-85

    // "The object representation of an object of type T is the sequence of N unsigned char objects
    // taken up by the object of type T, where N equals sizeof(T)."
    // http://eel.is/c++draft/basic.types#4
    const unsigned char* pc = reinterpret_cast<const unsigned char*>(pi) ;
    const unsigned char* pc2 = reinterpret_cast<const unsigned char*>(pi2) ;
    std::cout << "sizeof(int) == " << pc2 - pc << '\n' ;
}

http://coliru.stacked-crooked.com/a/81d767ebff806b56
other thoughts... (the book is likely wanting you to do it with pointer magic, though)

you can use the types that tell you. eg int32_t (these are from cstdint I think).
you can take an unsigned version of it, assign it 0xFFFFFFFFFFFFFFFFFFFFF or whatever and then take the rounded up lg to get how many bits... lg 65535 is what :) (15.999 or something like that for the 16 bit value)
you can take a union with a big char array, fill in the int and see what happens to the char array (abuse of union-hack)
probably several other ways as well.

Last edited on
1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;

int main()
{
   int bytes = 1, n = 1;
   while ( n <<= 8 ) bytes++;
   cout << bytes;
}


or even

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;

template<typename T> int bytes( T a[] ) { return reinterpret_cast<char*>( &a[1] ) - reinterpret_cast<char*>( &a[0] ); }

int main()
{
   int a[2];
   double d[2];
   cout << bytes( a ) << '\n';
   cout << bytes( d ) << '\n';
}
Last edited on
@lastchance,

Techincally right-shifting a negative value (which the last shift would do) or "shifting into the sign bit " (which the penultimate shift would do) is undefined. Also, it's undefined for the right operand of << to be equal (or greater) than the number of bits in the object, so it would be undefined to shift a char left by 8. http://eel.is/c++draft/expr.shift

Having said that, it works just fine for me!
Last edited on
If I'm shifting it 8 bits at a time is it possible to shift into the sign bit?
Good point. But it will shift "beyond" the sign bit on the last shift ... I have no idea if that contradicts the standard or not. Note that "shifting into the sign bit" is my (bad) wording. Read the link, it's pretty short.
Last edited on
Sadly, I couldn't think of a similarly-obscure way to do it for doubles. Still trying though ...
Set it to a negative value (should set it's bit 63, the sign bit). Load it's bit pattern into an unsigned long long. Do the shift trick in the opposite direction. Or is that assuming too much about it (we need to know it will fit into a long long and that the highest bit is the sign bit).
Last edited on
Read the link, it's pretty short.

I'm trying ... but it's been a long week at work! Glad I'm not a compiler writer !!!

The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled.
If E1 has an unsigned type, the value of the result is E1×2E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.


Err, right!

I'm seriously considering nominating the C++ standard for one of these:
http://www.plainenglish.co.uk/campaigning/awards.html
Last edited on
Yeah, I just read it again. I think we need a priest.
1
2
> int bytes = 1, n = 1;
> while ( n <<= 8 ) bytes++;


This would yield the number of bits used in the value representation of int, rounded upwards as a multiple of 8.

sizeof(int) is the number of unsigned char objects making up the object representation of int

Even if CHAR_BIT == 8, this would fail on esoteric architectures where the two are not equivalent: for instance, a Unisys mainframe where the object representation of int uses 48 bits, but the value representation uses only the first 40 bits.
@JLBorges, so what's your opinion on starting with a signed int with value 1, and shifting left by 8 until it drops off the left side. It will never actually occupy the sign bit (if even that's a UB situation), but it will in a sense "jump over" it.
Last edited on
> what's your opinion on starting with a signed int with value 1, and shifting left by 8 until it drops off the left side.

This will work when
a. CHAR_BIT == 8 (true everywhere, these days)
b. All bits in the object representation of int participate in its value representation (generally true).

See:
The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object of type T is the set of bits that participate in representing a value of type T. Bits in the object representation that are not part of the value representation are padding bits. For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values.
http://eel.is/c++draft/basic.types#4


For narrow character types, all bits of the object representation participate in the value representation.... For unsigned narrow character types, each possible bit pattern of the value representation represents a distinct number. These requirements do not hold for other types.
http://eel.is/c++draft/basic.types#basic.fundamental-1


It will never actually occupy the sign bit (if even that's a UB situation)
But the behavior is undefined. Leaving aside the fast that the signed representation may not be two's complement and may not have an actual sign bit:
1. If n > 0:
1.a. If (n << m) < 0 then you have to keep shifting.
1.b. If ((unsigned)n << m) == 0 then n << m has undefined behavior, as per
[if] E1×2^E2 is [not] representable in the corresponding unsigned type[, the behavior is undefined]
2. If n < 0, n << m is always undefined.

The only possible outcome of the algorithm is undefined behavior.
Last edited on
Is it any better if I started from the maximum representable value (from <limits>) and right-shifted 8 bits a time instead?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <limits>
using namespace std;

template<typename T> T bytes()
{
   T size = 0;
   for ( T n = numeric_limits<T>::max(); n; n /= 256 ) size++;
   return size;
}

int main()
{
   cout << "short: " << bytes<short>() << '\n';
   cout << "int: " << bytes<int>() << '\n';
   cout << "unsigned: " << bytes<unsigned>() << '\n';
   cout << "long long: " << bytes<long long>() << '\n';
   cout << "unsigned long long: " << bytes<unsigned long long>() << '\n';
}



But if using numeric_limits then I think @coder777 was hinting at this right at the beginning of the thread.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <limits>
using namespace std;

template<typename T> T bytes() { return ( numeric_limits<T>::digits + 1 ) / 8; }

int main()
{
   cout << "short: " << bytes<short>() << '\n';
   cout << "int: " << bytes<int>() << '\n';
   cout << "unsigned: " << bytes<unsigned>() << '\n';
   cout << "long long: " << bytes<long long>() << '\n';
   cout << "unsigned long long: " << bytes<unsigned long long>() << '\n';
}
Last edited on
Topic archived. No new replies allowed.