Сужение преобразования типов в C ++ с использованием указателей - PullRequest
0 голосов
/ 14 мая 2011

У меня были некоторые проблемы с нисходящим преобразованием типов в C ++ с использованием указателей, и, прежде чем я пришел к идее сделать это таким образом, Google в основном сказал мне, что это невозможно, и это не освещалось ни в одной книге, которую я изучал C ++. от. Я полагал, что это будет работать ...

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";

Инкремент в строке пять может быть неправильным, но вывод беспокоит меня, что мой компилятор C, который я использую gcc 3.4.2, автоматически превращает TheInt1 в long int или что-то в этом роде. Вывод выглядит так ...

Двойной номер 723330, который равен 723330 * 4067360

Выход из TheInt1 невероятно высок, а выход из TheInt2 отсутствует.

У меня три вопроса ...

Я даже на правильном пути?

Какой правильный шаг для пятой строки?

Почему, черт возьми, TheInt1 / TheInt2 допускает такое большое значение?

Ответы [ 3 ]

5 голосов
/ 14 мая 2011

int, вероятно, является 32-битным, что дает ему диапазон от -2 * 10 ^ 9 до 2 * 10 ^ 9.

В строке long int * pTheLong2 = &TheLong + 0x4; вы выполняете арифметику указателя на long int*, что означает, что адрес увеличится на размер 0x4 long int с.Я предполагаю, что вы предполагаете, что long int в два раза больше int.Это абсолютно не гарантировано, но, вероятно, верно, если вы компилируете в 64-битном режиме.Таким образом, вы хотите добавить к вашему указателю половину размера long int - ровно такого размера, как вы полагаете int.int * pTheLong2 = (int*)(&TheLong) + 1; достигает этого.

Вы на правильном пути, но, пожалуйста, имейте в виду, как уже отмечали другие, что вы сейчас изучаете неопределенное поведение.Это означает, что переносимость нарушена, и флаги оптимизации могут очень хорошо изменить поведение.


Кстати, более правильная вещь для вывода (при условии, что машина имеет младший порядок байтов) будет:

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

Для полноты картины хорошо определенное преобразование 32-разрядного целого числа в два 16-разрядных:

#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;
}

Вывод: 723330 = 2434 + 11 * 2^16

2 голосов
/ 14 мая 2011

Я даже на правильном пути?

Вероятно, нет.Вы, кажется, смущены.

Какое правильное приращение для пятой строки?

Там нет ни одного.Арифметика указателей возможна только внутри массивов, здесь у вас нет массивов.Так что

long int * pTheLong2 = &TheLong + 0x4;

- это неопределенное поведение, и любое значение, отличное от 0 (и, возможно, 1), которым вы замените 0x4, также будет UB./ TheInt2, допускающий такое большое значение?

int и long int часто имеют одинаковый диапазон возможных значений.

1 голос
/ 14 мая 2011
TheInt2 = *pTheLong2;

Это вызывает неопределенное поведение, потому что стандарт C ++ не дает какую-либо гарантию относительно того, на какую ячейку памяти указывает pTheLong2, поскольку она инициализируется как:

long int * pTheLong2 = &TheLong + 0x4;

&TheLong - это ячейка памяти переменной TheLong, а pTheLong2 инициализируется в ячейке памяти, которая либо не является частью программы, следовательно, недопустимой, либо указывает на ячейку памяти в самой программе, хотя вы не знаете, где именно, ни C ++ Standard не дает никакой гарантии, на что он указывает.

Следовательно, разыменование такого указателя вызывает неопределенное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...