#include <iostream>
int main()
{
constint i = 0 ;
constint* pi = &i ; // address of i
constint* 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#4constunsignedchar* pc = reinterpret_cast<constunsignedchar*>(pi) ;
constunsignedchar* pc2 = reinterpret_cast<constunsignedchar*>(pi2) ;
std::cout << "sizeof(int) == " << pc2 - pc << '\n' ;
}
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.
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
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.
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).
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.
> 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.
> 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.