Преобразование типов

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

int a   = 1;
float b = 2.0f;
float c = b + a; // a converts to float

Символьная переменная char представляет собой число.

char letter = 'A'; // 'A' is 65 in ASCII

Стандарт при этом ничего не говорит о том, является ли char беззнаковым, и в зависимости от компилятора реализация может быть разной. Для стандартной части ASCII (первые 127 символов) гарантируется, что при преобразовании из char в int результатом будет положительное число, а вот расширение ASCII на разных системах может дать как положительное, так и отрицательное. Если требуется хранить информацию не символьного характера, то имеет смысл явно указать знаковость при помощи модификатора.

Преобразования от более «широких» к более «узким» в общем случае происходит с потерей данных.

4 июля 1996 года из Французской Гваины была запущена ракета Arian V, разработка которой заняла 10 лет и стоила Европейскому Союзу порядка 7 млрд. долларов, вместе с полезной нагрузкой стоимостью 500 млн. долларов. На 34-й секунде полёта ракета взорвалась по причине ошибки в программном обеспечении: при попытке сконвертировать 64-битную переменную с плавающей запятой, отвечающую за горизонтальную скорость, в 16-битное число со знаком произошло переполнение регистра (число оказалось больше 32767, т.е. максимально допустимого для 16-битной переменной), что привело к исключительной ситуации и краху всей системы, так как проверка переполнения была отключена. ПО было написано на языке Ада.

uint32_t a = 1023;
uint8_t  b =    a; // b == 255

Большинство компиляторов при подобных преобразованиях выводят предупреждения. И несмотря на это, ошибки, связанные с преобразованием типов, одни из самых распространенных: программист самостоятельно должен отслеживать диапазоны. При преобразовании более «широких» к более «узким» типов лучше всего указывать преобразование явным способом, например так:

#define MM_PER_INCH               25.4f
uint8_t a = (uint8_t)(MM_PER_INCH);

Изменено:

Язык Си: 6 комментариев

  1. >Вместо нуля может быть почти любой другой символ. Плюс и минус работают по-другому. Для выравнивания числа по по левому краю, а не по правому, перед числом нужно поставить знак минус.
    Лишне по

  2. Термин «регистр ядра» довольно специфичен. Звучит не привычно. А почему не использовать термин CPU или процессор или на худой конец микроконтроллер?

  3. Смысл статических переменных вне функции мне кажется не раскрыт. Такой модификатор делает переменную недоступной из других единиц трансляции. Т.е. не будет конфликта имен между разными .с файлами.

  4. #ifdef STM8
    ind.i = 250;
    #elif STM32
    ind.j = 1027;

    Точно #elif ? Что-то мне подсказывает, что здесь должно быть либо #else #ifdef STM32, либо просто #ifdef STM32

  5. «printf(«a\t: 10\n\r»);
    printf(«ab\t: 11\n\r»);
    printf(«abc\t: 12\n\r»);
    // a___: 10
    // ab__: 10
    // abc_: 10″

    Не понял, почему 10 в выводе в каждой строке?

  6. «Для вывода чисел с плавающей запятой приведённые выше опции так же работают, но добавляются и другие. Например, если нам нужно ограничиться выводом сотых, нужно написать точку и цифру 2. При чём обратите внимание число будет округлятся в большую сторону.

    float pi = 3.1415926;
    printf(«%.0f\n\r», pi); // 3
    printf(«%.1f\n\r», pi); // 3.1
    printf(«%.2f\n\r», pi); // 3.14
    printf(«%.3f\n\r», pi); // 3.142
    printf(«%.4f\n\r», pi); // 3.1416″

    В то же время:
    «printf(«%.1f\n\r», pi); // 3.1
    printf(«%.2f\n\r», pi); // 3.14″

    Насколько я вижу, округление происходит по математическим правилам, в том числе при округлении пятерки. Где ошибка: в примере или в описании?

Добавить комментарий

Ваш адрес email не будет опубликован.