Как компиляторы C / C ++ обрабатывают приведение типов между типами с различными диапазонами значений?

Алиасы столбцов определяют имена для выхода для SELECT.

Чтобы использовать их в самом предложении SELECT, вам необходимо добавить еще один слой косвенности:

SELECT c1 FROM (SELECT 42 AS c1)
13
задан jww 8 March 2018 в 14:49
поделиться

4 ответа

Ну, сначала обратите внимание, что бросок явный запрос для преобразования значения одного типа к значению другого типа . Бросок будет также всегда производить новый объект, который является временным файлом, возвращенным оператором броска. Кастинг к ссылочному типу, однако, не создаст новый объект. Объекту, на который ссылается значение, дают иное толкование как ссылка другого типа.

Теперь к Вашему вопросу. Обратите внимание, что существует два главных типа преобразований:

  • Продвижения : об Этом типе можно думать кастинга от возможно более узкого типа до более широкого типа. При кастинге от символа до интервала, короткого к интервалу, плавание для удвоения является всеми продвижениями.
  • Преобразования : Они позволяют бросать от долго до интервала, интервала к неподписанному интервалу и т.д. Они могут в принципе вызвать потерю информации. Существуют правила для того, что происходит, если Вы присваиваетесь -1 к неподписанному типизированному объекту, например. В некоторых случаях неправильное преобразование может привести к неопределенному поведению. При присвоении двойного большего, чем, что плавание может сохранить к плаванию, поведение не определяется.

Позволяют нам посмотреть на Ваши броски:

int i = 10; 
unsigned int k = (unsigned int) i; // :1

float fl = 10.123;
unsigned int  ufl = (unsigned int) fl; // :2

char *p = "Stackoverflow Rocks"; 
unsigned char *up = (unsigned char *) p; // :3
  1. Этот бросок заставляет преобразование происходить. Никакой потери данных не происходит, с тех пор 10, как гарантируют, будет сохранен unsigned int. Если бы целое число было отрицательно, значение в основном перенесло бы максимальное значение неподписанного интервала (см. 4.7/2).
  2. значение 10.123 является усеченным к 10. Здесь, это делает причина, потерянная информации, очевидно. Как 10 вписывается в неподписанный интервал, поведение определяется.
  3. Это на самом деле требует большего внимания. Во-первых, существует преобразование устаревшее от строкового литерала до char*. Но давайте проигнорируем это здесь. (см. здесь ). Что еще более важно, что действительно происходит, если Вы бросаете к неподписанному типу? На самом деле результат этого является неуказанным на [1 124] 5.2.10/7 (обратите внимание, что семантика того броска совпадает с использованием reinterpret_cast в этом случае, так как это - единственная способность броска C++ сделать это):

указатель А на объект может быть явно преобразован в указатель на объект другого типа. За исключением того, что, преобразовывая rvalue типа “pointer к T1” к типу "указатель на T2" (где T1 и T2 являются типами объектов и где требования выравнивания T2 не более строги, чем те из T1) и назад к его исходному типу приводит к исходному значению указателя, результат такого преобразования указателя является неуказанным.

, Таким образом, Вы только в безопасности использовать указатель после того, как Вы вспомните char * снова.

20
ответ дан Community 8 March 2018 в 14:49
поделиться
  • 1
    Хорошо, как насчет вложенных таблиц? Внешняя таблица имеет float:left и одну ячейку. В той ячейке существует внутренняя таблица с float:right и двумя ячейками. В каждой из этих двух ячеек содержание Ваших двух внутренних отделений. It' s более включенный, чем просто отделения, но это работает (над моим XP/IE7, по крайней мере). – Oren Shalev 12 May 2009 в 12:40

Броски имеют в виду разные вещи в зависимости от того, каковы они. Они могут просто быть переименованиями типа данных без изменения в представленных битах (большинство бросков между целочисленными типами, и указатели похожи на это), или преобразования, которые даже не сохраняют длину (такой как между двойным и международным на большинстве компиляторов). Во многих случаях значение броска является просто неуказанным, означая, что компилятор должен сделать что-то разумное, но не должен документировать точно что.

бросок А не должен даже приводить к применимому значению. Что-то как char * cp; float * fp; cp = malloc(100); fp = (float *)(cp + 1); почти наверняка приведет к неправильно выровненному указателю на плавание, которое разрушит программу в некоторых системах, если программа попытается использовать его.

1
ответ дан David Thornley 8 March 2018 в 14:49
поделиться
  • 1
    Несомненно, that’s другое обходное решение. Работы хорошо, если Вы знаете, насколько широкий дочерний элемент будет. – Paul D. Waite 2 April 2012 в 14:57

Два броска C-стиля в Вашем примере являются различными видами броска. В C++ Вы обычно писали бы им

unsigned int uf1 = static_cast<unsigned int>(fl);

и

unsigned char* up = reinterpret_cast<unsigned char*>(p);

, первое выполняет арифметический бросок, который усекает число с плавающей точкой, таким образом, существует потеря данных.

второе не вносит изменений в данные - они просто дают компилятору команду рассматривать указатель как другой тип. Необходимо соблюдать осторожность об этом виде броска: это может быть очень опасно.

8
ответ дан James Hopkin 8 March 2018 в 14:49
поделиться
  • 1
    К сожалению, таблица, кажется, вынуждает дочерние отделения перенестись, таким образом, they' ре друг выше друга вместо стороны для запасного пути. – Paul D. Waite 12 May 2009 в 11:30

"Введите" в C, и C++ является свойством, присвоенным переменным, когда они обрабатываются в компиляторе. Свойство больше не существует во времени выполнения, за исключением виртуальных функций/RTTI в C++.

компилятор использует тип переменных для определения большого количества вещей. Например, в присвоении плавания к интервалу, это будет знать, что должно преобразовать. Оба типа - вероятно, 32 бита, но с различными значениями. Вероятно, что ЦП имеет инструкцию, но иначе компилятор знал бы для вызова функции преобразования. Т.е. & __stack[4] = float_to_int_bits(& __stack[0])

преобразование из символа* к неподписанному символу* даже simpeler. Это - просто различная маркировка. На разрядном уровне, p и идентичны. Компилятор просто должен помнить, что *p требует расширения знака, в то время как *не делает.

5
ответ дан MSalters 8 March 2018 в 14:49
поделиться
  • 1
    Да, извините: код выше является просто примером кода для выделения ошибки. Я использовал встроенные стили для создания немного легче видеть, что what’s продолжается. – Paul D. Waite 15 May 2009 в 10:33