开发者

Narrowing type conversion in C++ using pointers

I have been having some problems with downward type conversion in C++ using pointers, and before I came up with the idea of doing it this way Google basically told me this is impossible and it wasn't covered in any books I learned C++ from. I figured this would work...

long int TheLong=723330;
int TheInt1=0;
int TheInt2=0;开发者_运维技巧
long int * pTheLong1 = &TheLong;
long int * pTheLong2 = &TheLong + 0x4;

TheInt1 = *pTheLong1;
TheInt2 = *pTheLong2;

cout << "The double is " << TheLong << " which is "
     << TheInt1 << " * " << TheInt2 << "\n";

The increment on line five might not be correct but the output has me worried that my C compiler I am using gcc 3.4.2 is automatically turning TheInt1 into a long int or something. The output looks like this...

The double is 723330 which is 723330 * 4067360

The output from TheInt1 is impossibly high, and the output from TheInt2 is absent.

I have three questions...

Am I even on the right track?

What is the proper increment for line five?

Why the hell is TheInt1/TheInt2 allowing such a large value?


int is probably 32 bit, which gives it a range of -2*10^9 to 2*10^9.

In the line long int * pTheLong2 = &TheLong + 0x4; you are doing pointer arithmetic to a long int*, which means the address will increase by the size of 0x4 long ints. I guess you are assuming that long int is twice the size of int. This is absolutely not guaranteed, but probably true if you are compiling in 64 bit mode. So you want to add half the size of a long int -- exactly the size of an int under your assumption -- to your pointer. int * pTheLong2 = (int*)(&TheLong) + 1; achieves this.

You are on the right track, but please keep in mind, as others have pointed out, that you are now exploring undefined behaviour. This means that portability is broken and optimization flags may very well change the behaviour.


By the way, a more correct thing to output (assuming that the machine is little-endian) would be:

cout << "The long is " << TheLong << " which is "
     << TheInt1 << " + " << TheInt2 << " * 2^32" << endl;

For completeness' sake, a well-defined conversion of a 32 bit integer to two 16 bit ones:

#include <cstdint>
#include <iostream>

int main() {
    uint32_t fullInt = 723330;
    uint16_t lowBits  = (fullInt >>  0) & 0x0000FFFF;
    uint16_t highBits = (fullInt >> 16) & 0x0000FFFF;

    std::cout << fullInt << " = "
        << lowBits << " + " << highBits << " * 2^16"
        << std::endl;

    return 0;
}

Output: 723330 = 2434 + 11 * 2^16


Am I even on the right track?

Probably not. You seem confused.

What is the proper increment for line five?

There are none. Pointer arithmetic is possible only inside arrays, you have no arrays here. So

long int * pTheLong2 = &TheLong + 0x4;

is undefined behavior and any value other than 0 (and possibly 1) by which you'd replace 0x4 would also be UB.

Why the hell is TheInt1/TheInt2 allowing such a large value?

int and long int often have the same range of possible values.


TheInt2 = *pTheLong2;

This invokes undefined behavior, because the C++ Standard does not give any guarantee as to which memory location pTheLong2 is pointing to, as it's initlialized as:

long int * pTheLong2 = &TheLong + 0x4;

&TheLong is a memory location of the variable TheLong and pTheLong2 is initialized to a memory location which is either not a part of the program hence illegal, or its pointing to a memory location within the program itself, though you don't know where exactly, neither the C++ Standard gives any guarantee where it's pointing to.

Hence, dereferencing such a pointer invokes undefined behavior.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜