ПрограммированиеФорумОбщее

Приведение типов в выражениях C/C++ (комментарии)

Страницы: 1 2 Следующая »
#0
13:05, 7 янв 2012

Приведение типов в выражениях C/C++ (комментарии)

Это сообщение сгенерировано автоматически.

#1
13:05, 7 янв 2012

Интересно. Нелогично сделано в x86 есть sub al,bl итд, можно работать с разрядностью 8,16,32,64

#2
13:15, 7 янв 2012

Когда есть онлайн компиляторы, то уже следует прикладывать тесты:
http://liveworkspace.org/code/de5b8f4d940fe5d16f29da20b8ec5b07
http://liveworkspace.org/code/6af8c65278eabf14baaf1f7911b79399

>Порой кажется, что приведение типа явно лишнее, но на самом деле оно необходимо:
>unsigned short time = 5;
>unsigned short last_time = 65531;
>float delta_time2 = (float) (unsigned short) (time - last_time);
>// в скобках int (-65526), далее приведение к unsigned short (10), результат равен 10.0f
Вы так говорите, как будто 5-65531 равно 10.

#3
13:18, 7 янв 2012

laMer007
> Вы так говорите, как будто 5-65531 равно 10.

Для unsigned типов в нормальных языках оно равно Integer Overflow

#4
13:21, 7 янв 2012

Абрам Софтрендер
> Для unsigned типов в нормальных языках оно равно Integer Overflow
В MS VS 2008 в настройках компиляции есть ключ, отвечающий за обнаружение таких Integer Overflow в debug.

#5
13:31, 7 янв 2012

  Я провёл тщательный тест, над которым можно задуматься. http://ideone.com/QMIil

#include <stdio.h>
#include <stdint.h>
#include <time.h>

int main () {
  unsigned short c1 = 100500;                           // warning
  unsigned short c2 = (int)((int16_t)5 - (int16_t)7);   // no warning

  printf("%d\n", (int16_t)5 - (int16_t)7);              // -2
  printf("%u\n", (int16_t)5 - (int16_t)7);              // 4294967294
  printf("%d\n", (int16_t)65534);                       // -2
  puts("");
  printf("%d\n", (uint16_t)5 - (uint16_t)7);            // -2
  printf("%u\n", (uint16_t)5 - (uint16_t)7);            // 4294967294
  printf("%d\n", (uint16_t)65534);                      // 65534
  puts("");
  printf("%hd\n", (int16_t)40000 + (int16_t)40000);     // 14464
  printf("%d\n",  (int16_t)40000 + (int16_t)40000);     // -51072
  printf("%u\n",  (int16_t)40000 + (int16_t)40000);     // 4294916224
  puts("");
  printf("%hd\n", (uint16_t)40000 + (uint16_t)40000);   // 14464
  printf("%d\n",  (uint16_t)40000 + (uint16_t)40000);   // 80000
  printf("%u\n",  (uint16_t)40000 + (uint16_t)40000);   // 80000
  puts("");
  printf("%hd\n", (int16_t)30000 + (int16_t)30000);     // -5536
  printf("%d\n",  (int16_t)30000 + (int16_t)30000);     // 60000
  printf("%u\n",  (int16_t)30000 + (int16_t)30000);     // 60000
  puts("");
  printf("%hd\n", (uint16_t)30000 + (uint16_t)30000);   // -5536
  printf("%d\n",  (uint16_t)30000 + (uint16_t)30000);   // 60000
  printf("%u\n",  (uint16_t)30000 + (uint16_t)30000);   // 60000
  puts("");
  printf("%d\n", sizeof((int16_t)5 - (int16_t)7) );     // 4

  return 0;
}

Правила, по которым приведение осуществляется до или после операции беспощадны по своей бесмысленности. А как ещё можно получить 80000, сложив (uint16_t)40000 и (uint16_t)40000, но при этом не получить того же, складывая типы int16_t у меня в голове не укладывается. Хотя, кажется с этим понятно. Есть ещё вопросы, буду пока разбираться.
  Ещё gcc мухлюет, передавая в printf тот тип, который указан в форматной строке, в то время как он должен хотя бы выдавать предупреждение, потому что при попытке вывести одно и то же число через %d и %hd где-то должна возникать ошибка, потому что в рантайме неизвестно, что лежит в списке аргументов, но они нормально выводятся.

  В целом складывается впечатление, что операнды приводятся к инту ещё до операции, аналогично тому, как это происходит в Java. Только там об этом поведении все знают, так как нельзя неявно привести int к short, а тут можно, о чём говорит вторая строчка в main.

#6
13:38, 7 янв 2012

laMer007
> Вы так говорите, как будто 5-65531 равно 10
Оно и равно, по модулю 65536 )

#7
14:02, 7 янв 2012

Zefick
> http://ideone.com/QMIil
> Правила, по которым приведение осуществляется до или после операции беспощадны по своей бесмысленности.
Вы же понимаете, что указывать типы результатов, которых вы не знаете, вручную в printf было очень глупо:

 unsigned short c = 100500;  // warning

  cout<< ((int16_t)5 - (int16_t)7)<<endl;              // -2
  cout<< ((int16_t)5 - (int16_t)7)<<endl;             // -2
  cout<< ((int16_t)65534 + (int16_t)0)<<endl;           // -2
  cout<<endl;
  cout<< ((uint16_t)5 - (uint16_t)7)<<endl;             // -2
  cout<< ((uint16_t)5 - (uint16_t)7)<<endl;             // -2
  cout<< ((uint16_t)65534 + (uint16_t)0)<<endl;         // 65534
  cout<<endl;
  cout<< ((int16_t)40000 + (int16_t)40000)<<endl;      // -51072
  cout<< ((int16_t)40000 + (int16_t)40000)<<endl;      // -51072
  cout<< ((int16_t)40000 + (int16_t)40000)<<endl;      // -51072
  cout<<endl;
  cout<< ((uint16_t)40000 + (uint16_t)40000)<<endl;    // 80000
  cout<< ((uint16_t)40000 + (uint16_t)40000)<<endl;    // 80000
  cout<< ((uint16_t)40000 + (uint16_t)40000)<<endl;    // 80000
  cout<<endl;
  cout<< ((int16_t)30000 + (int16_t)30000)<<endl;      // 60000
  cout<< ((int16_t)30000 + (int16_t)30000)<<endl;      // 60000
  cout<< ((int16_t)30000 + (int16_t)30000)<<endl;      // 60000
  cout<<endl;
  cout<< ((uint16_t)30000 + (uint16_t)30000)<<endl;    // 60000
  cout<<  ((uint16_t)30000 + (uint16_t)30000)<<endl;    // 60000
  cout<<  ((uint16_t)30000 + (uint16_t)30000)<<endl;    // 60000
  cout<< endl;
  cout<<  (sizeof((int16_t)5 - (int16_t)7) )<<endl;      // 4

http://liveworkspace.org/code/51e0e36576c742233f32e503b8bb5e01

#8
14:15, 7 янв 2012

laMer007
> Вы так говорите, как будто 5-65531 равно 10
да, равно. старшие разряды выбрасываются т.к. вместимость unsigned short не позволяет их вместить.
0 == 65536 == 2*65536 == ... = 2^(16+n)
В m-битном числе 0 == 2^(m+n)

Zefick
> Правила, по которым приведение осуществляется до или после операции беспощадны
> по своей бесмысленности
правила абсолютно логичны.

> А как ещё можно получить 80000, сложив (uint16_t)40000 и (uint16_t)40000, но
> при этом не получить того же, складывая типы int16_t
в обоих случаях складываются 40000 + 40000, работаем в 32-битной системе, поэтому

  0000 0000 0000 0000 1001 1100 0100 0000     40000

+ 0000 0000 0000 0000 1001 1100 0100 0000    40000
= 0000 0000 0000 0001 0011 1000 1000 0000      80000 = 65536 + 14464

Если в printf вписан %h (16-битный), то красная единичка выбрасывается (не влезает) и результат приводится к uint16_t, в который попадает только то, что выделено жирным, то есть 14464.
#9
14:27, 7 янв 2012

ALPINE
> да, равно. старшие разряды выбрасываются
Вы пропагандируете в своей статье насильный кастинг к меньшему типу, как крайне полезный приём, в то время, как результат мы получаем во float. Зачем, спрашивается? (:

>>(int16_t)40000 + (int16_t)40000); // -51072
> Враньё, у меня выводится 80000 и это логично.
http://ideone.com/Ypu45
Что-за у вас убогий компилятор? Вы не поверите, но он не смог откастить 40000 до int16_t:
http://ideone.com/KoK2n

#10
14:33, 7 янв 2012

laMer007
> Вы же понимаете, что указывать типы результатов, которых вы не знаете, вручную
> в printf было очень глупо:
к типу, указанному в printf, результаты будут приводиться.

P.S. а cout всё выводит в "обычном int" (signed int, 32 бит)

#11
14:34, 7 янв 2012

laMer007
> результат мы получаем во float. Зачем, спрашивается? (:
просто для примера. я в своём проекте упёрся именно в это (и я как раз умножал на флоат-коэффициент) и решил изложить грабли, на которые сам же и наступил.

laMer007
насчёт вранья сорри, всё ок, я перепутал int16_t и uint16_t - буковку "u" пропустил. с этим всё в порядке.

P.S. Проанализировал всё, для меня теперь абсолютно всё понятно и логично. Спрашивайте, разъясню :)

#12
15:04, 7 янв 2012

ALPINE
> в обоих случаях складываются 40000 + 40000, работаем в 32-битной системе, поэтому
  Я имел в виду случай где результат -51072. А просиходит там следующее: 40000 сначала приводится к short и получается -25536. Затем это приводится к инту и складывается. Теперь всё логично, просто поведение printf запутывает, хотя я и сам тут накосячил. На самом деле компилятор не должен пытаться привести типы и анализировать форматную строку должен максимум для выдачи предупреждений.

  Кстати, одному мне кажется, что название подсказки какое-то неправильное? Даже если вставить "неявные приведения", то всё равно что-то не то.

#13
15:06, 7 янв 2012

ALPINE
> к типу, указанному в printf, результаты будут приводиться.
Вообще то мы хотели узнать реальный результат и тип выражения, а не указанный вручную.

> к типу, указанному в printf, результаты будут приводиться.
"Только между signed/unsigned в пределах целочисленного типа одного размера". В остальных случаях UB.

> P.S. а cout всё выводит в "обычном int" (signed int, 32 бит)
cout все выводит с тем типом, который реально является типом результата выражения.

#14
15:18, 7 янв 2012

Zefick
> Кстати, одному мне кажется, что название подсказки какое-то неправильное?
да... поправил, так вроде лучше.

laMer007
> Вообще то мы хотели узнать реальный результат и тип выражения, а не указанный вручную.
результирующим типом "по умолчанию" всегда будет int

> "Только между signed/unsigned в пределах целочисленного типа одного размера"
signed/unsigned и отсечение старших разрядов.

> cout все выводит с тем типом, который реально является типом результата выражения
...то есть в int :)

P.S. для 64-битных приложений это естественно будет __int64

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.