реклама на сайте
подробности

 
 
> Понятие стандартного типа и тип операндов..., 16/32битный Cи компилятор. Хочу раз и на всегда уточнить.
sigmaN
сообщение Nov 28 2009, 00:06
Сообщение #1


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Имеем код
Код
uint32_t a = 320 * 240;

Компилятор будет трактовать операнды 320 и 240 как имеющие тип int? Результат будет зависеть от разрядности int(16/32), правильно я понимаю?
И вообще, когда говорят "16ти битный компилятор" имеют ввиду именно разрядность int?
На C2000 int 16ти битный и a получается == 11264, хотя на самом деле должно быть 76800.
А что,если так?
Код
uint32_t a = (uint32_t)320 * 240;
чё получим?

или так
Код
uint32_t a = 320 * (uint32_t)240;


ну так то понятно, что всё будет OK
Код
uint32_t a = (uint32_t)320 * (uint32_t)240;


Сбивает ещё то, что в какой-то книге довелось прочитать, что тип будет взят от первого операнда... потом на форуме видел, что такие вещи компилятор трактует как имеющие стандартный тип(есть вообще такое понятие?).

Копнуть ISO/IEC 9899:1999 пытался, но без привычки это достаточно сложно....

Тему поднял потому, что как-бы о портируемости думать тоже нужно, а с этим типом int и его длиной бывают приколы, как я понял....


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 14)
DpInRock
сообщение Nov 28 2009, 04:23
Сообщение #2


Гуру
******

Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515



Цитата
Компилятор будет трактовать операнды 320 и 240 как имеющие тип int?

Как uint32_t.
А вот что такое uint32_t - надо смотреть где это тип определяется.

Интуитивно можно догадаться, что это некий UNSIGNED тип.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
baralgin
сообщение Nov 28 2009, 08:59
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680



Цитата(sigmaN @ Nov 28 2009, 02:06) *
А что,если так?
Код
uint32_t a = (uint32_t)320 * 240;
чё получим?
или так
Код
uint32_t a = 320 * (uint32_t)240;

ну так то понятно, что всё будет OK
Код
uint32_t a = (uint32_t)320 * (uint32_t)240;

Ну очевидно, что все эти варианты будут работать правильно. Кстати тулз 5.2.1 для первого примера( 320 * 240 ) выдаёт warning: "integer operation result is out of range". Значит он их определяет как int. В данном случае можно писать красивее:
Код
uint32_t a = 320L * 240;

Как там в стандарте сам не знаю smile.gif .

ps: uint32_t тут должен определяться как unsigned long.
Go to the top of the page
 
+Quote Post
dxp
сообщение Nov 28 2009, 09:39
Сообщение #4


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(sigmaN @ Nov 28 2009, 06:06) *
Имеем код
Код
uint32_t a = 320 * 240;

Компилятор будет трактовать операнды 320 и 240 как имеющие тип int? Результат будет зависеть от разрядности int(16/32), правильно я понимаю?

Да, int - платформеннозависимый тип. Для определенности вы можете, например, написать:
Код
uint32_t a = 320ul * 240;


Но я бы сделал так:

Код
const uint32_t X_SIZE = 320;
const uint32_t Y_SIZE = 240;
uint32_t a = 320 * 240;


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
SM
сообщение Nov 28 2009, 10:43
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(dxp @ Nov 28 2009, 12:39) *
Но я бы сделал так:


а я бы просто

uint32_t a = 320L * 240L;
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 28 2009, 11:03
Сообщение #6


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



На самом деле смысл там такой - если все операнды помещаются в int, то операция и производится как int (а если калибр операндов меньше, чем int, они к нему приводятся, это называется integer promotion) . Калибр int'а, естественно, зависит от платформы.

Соответственно, оба операнда (320 и 240) в int помещаются и операция производится в калибре int, только вот результат произведения не лезет. Достаточно указать, что один из операндов 32хбитный и все будет хорошо.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2009, 11:03
Сообщение #7


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Ну uint32_t я намеренно использовал для того, чтобы однозначно определить, что это именно unsigned 32бита.

uint32_t a = 320L * 240L;

Ну так а на другом компиляторе, где long будет 64бит - будет уже оверхед?

Ну с const'ами то ясно, что самый правильный вариант.

Ну а вообще, как оно в стандарте то?
Цитата
Да, int - платформеннозависимый тип. Для определенности вы можете, например, написать:
Код
uint32_t a = 320ul * 240;
А почему достаточно первый определить как ul и всё работает? А если операнда три? А если не левый, а крайний правый сделать ul
ну типа uint32_t a = 320 * 240 * 2ul;

Как вообще по стандарту? Что сказано о таких случаях?


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
Andron_
сообщение Nov 28 2009, 11:12
Сообщение #8


.NET developer
***

Группа: Свой
Сообщений: 218
Регистрация: 20-10-07
Из: Новосибирск
Пользователь №: 31 532



Цитата
Ну так а на другом компиляторе, где long будет 64бит - будет уже оверхед?

в компиляторов для настольных ПК 64 бита - это long long))

а long = int = 32 бита...


uint32_t a = 320 * 240;

компилятор будет рассматривать обе константы как типа int. если int 16 бит - будет переполнение...

если операндов несколько... компилятор определяет самый "длинный" или "сложный" тип среди операндов и все приводит к нему. После выполнения операции он начинает думать, как его привести к переменной, которой ему нужно присвоить результат.
Go to the top of the page
 
+Quote Post
SM
сообщение Nov 28 2009, 11:59
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(sigmaN @ Nov 28 2009, 14:03) *
Ну так а на другом компиляторе, где long будет 64бит - будет уже оверхед?

Не будет оверхеда, так как результат все равно обкоцают до uint32, и оптимизатор, понимая это, воткнет константу наиболее оптимального для платформы типа.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2009, 12:05
Сообщение #10


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Цитата
в компиляторов для настольных ПК 64 бита - это long long))
oops, чё-то я малёк запутался уже smile.gif

Цитата
если операндов несколько... компилятор определяет самый "длинный" или "сложный" тип среди операндов и все приводит к нему. После выполнения операции он начинает думать, как его привести к переменной, которой ему нужно присвоить результат.
Вооот. Вот это то, что хотелось знать. СПАСИБО! smile.gif

А ещё вопросик: если в выражении есть скобки это что-то меняет? Я имею ввиду выбирать самый длинный и сложный он будет не смотря на скобки? А то был у меня один странный случай, я там вроде указал самого жирного, а чё-т не работало, пока всёх явно к 32бит типу не привёл.... Щас уже не вспомню толком где это было... Показал бы конкретное выражение. Там были скобки, точно помню. Ещё тогда подумал, что что-то я не понял в этой жизни smile.gif


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Nov 28 2009, 12:23
Сообщение #11


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Цитата
если операндов несколько... компилятор определяет самый "длинный" или "сложный" тип среди операндов

Неправильно.

В указанном порядке (например, для операции умножения - сдева направо) вычисляются выражения над двумя операндами.
И, соответственно, promotion выполняется для первой пары операндов. К вычислению второго умножения приходит в качестве левого операнда то, что получилось в результате умножения (с наиболее "старшим" типом из операндов), затем делается "продвижение" среди пары ыторых.
То есть, в выражении

2 * 3L * 4.0

сперва 2 делается long, потом умножается на 3, затем результат делается float и умножается на 4.

Скобки, естественно, меняют порядок вычислений.

Сообщение отредактировал Genadi Zawidowski - Nov 28 2009, 12:28
Go to the top of the page
 
+Quote Post
Andron_
сообщение Nov 28 2009, 12:44
Сообщение #12


.NET developer
***

Группа: Свой
Сообщений: 218
Регистрация: 20-10-07
Из: Новосибирск
Пользователь №: 31 532



гмммммм... ну ваще-то да... как-то оно так.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 28 2009, 14:54
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(DpInRock @ Nov 28 2009, 06:23) *
А вот что такое uint32_t - надо смотреть где это тип определяется.

Интуитивно можно догадаться, что это некий UNSIGNED тип.
Этот тип определен в stdint.h, означает 32-битовое беззнаковое целое и вместе со всем содержимым stdint.h описан в стандарте C99.

Цитата(sigmaN @ Nov 28 2009, 14:05) *
Я имею ввиду выбирать самый длинный и сложный он будет не смотря на скобки?
Еще раз уточним. Операции бывают унарные (один операнд, x = ~y), бинарные (два операнда, x = y * z) и тернарные (такая только одна: x = y ? z : i). Все выражение разбивается на эти примитивы в соответствии с приоритетом операций. Естественно, скобки влияют на приоритет. Т.е. выражение a = b * c * d - это на самом деле три выражения:
tmp1 = b * c;
tmp2 = tmp1 * d;
operator = (a, tmp2);
И для каждого из них отдельно применяются правила неявных приведений типов.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 28 2009, 20:47
Сообщение #14


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(dxp @ Nov 28 2009, 12:39) *
Но я бы сделал так: ....
Так будет корректней:
Код
static const uint32_t X_SIZE = 320UL;
static const uint32_t Y_SIZE = 240UL;
uint32_t a = X_SIZE * Y_SIZE;
Без статика возможны "игры разума" компиляторов...
И ещё, никакого оверхеда быть не может, т.к. константные выражения вычислятся при компиляции.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Злодей
сообщение Nov 28 2009, 20:57
Сообщение #15


Частый гость
**

Группа: Участник
Сообщений: 149
Регистрация: 29-04-08
Из: Петербург
Пользователь №: 37 142



Код
const uint32_t X_SIZE = 320;
const uint32_t Y_SIZE = 240;
uint32_t a = X_SIZE * Y_SIZE;


А можно как-нибудь так, чтобы 240 хранилось в int8 или int16, а то int32 как-то накладно выглядит.

P.S: На случай, если они перестанут быть константными или поучаствуют ещё-где-нибудь.

Сообщение отредактировал Злодей - Nov 28 2009, 21:05
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 04:52
Рейтинг@Mail.ru


Страница сгенерированна за 0.01518 секунд с 7
ELECTRONIX ©2004-2016