Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Понятие стандартного типа и тип операндов...
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
sigmaN
Имеем код
Код
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 и его длиной бывают приколы, как я понял....
DpInRock
Цитата
Компилятор будет трактовать операнды 320 и 240 как имеющие тип int?

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

Интуитивно можно догадаться, что это некий UNSIGNED тип.
baralgin
Цитата(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.
dxp
Цитата(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;
SM
Цитата(dxp @ Nov 28 2009, 12:39) *
Но я бы сделал так:


а я бы просто

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

Соответственно, оба операнда (320 и 240) в int помещаются и операция производится в калибре int, только вот результат произведения не лезет. Достаточно указать, что один из операндов 32хбитный и все будет хорошо.
sigmaN
Ну 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;

Как вообще по стандарту? Что сказано о таких случаях?
Andron_
Цитата
Ну так а на другом компиляторе, где long будет 64бит - будет уже оверхед?

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

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


uint32_t a = 320 * 240;

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

если операндов несколько... компилятор определяет самый "длинный" или "сложный" тип среди операндов и все приводит к нему. После выполнения операции он начинает думать, как его привести к переменной, которой ему нужно присвоить результат.
SM
Цитата(sigmaN @ Nov 28 2009, 14:03) *
Ну так а на другом компиляторе, где long будет 64бит - будет уже оверхед?

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

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

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

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

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

2 * 3L * 4.0

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

Скобки, естественно, меняют порядок вычислений.
Andron_
гмммммм... ну ваще-то да... как-то оно так.
Сергей Борщ
Цитата(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);
И для каждого из них отдельно применяются правила неявных приведений типов.
demiurg_spb
Цитата(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;
Без статика возможны "игры разума" компиляторов...
И ещё, никакого оверхеда быть не может, т.к. константные выражения вычислятся при компиляции.
Злодей
Код
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: На случай, если они перестанут быть константными или поучаствуют ещё-где-нибудь.
demiurg_spb
Цитата(Злодей @ Nov 28 2009, 23:57) *
А можно как-нибудь так, чтобы 240 хранилось в int8 или int16, а то int32 как-то накладно выглядит.
P.S: На случай, если они перестанут быть константными или поучаствуют ещё-где-нибудь.
Можно через дефайн. Но потребуется явно приводить их к соответствующему типу для исключения переполнения.
А можно и наоборот приводить к байту или слову в требуемых случаях, когда константы объявлены как UL.
Но проблема ИМХО надуманная. Как это так, они вдруг перестанут быть константами?
Ну а с квалификатором ststic const константы не занимают память вовсе, пока в программе не производится взятие адреса этой константы.
sigmaN
Цитата
Все выражение разбивается на эти примитивы в соответствии с приоритетом операций. Естественно, скобки влияют на приоритет. Т.е. выражение a = b * c * d - это на самом деле три выражения:
tmp1 = b * c;
tmp2 = tmp1 * d;
operator = (a, tmp2);
И для каждого из них отдельно применяются правила неявных приведений типов.
Вот он, момент истины smile.gif спасибо
sonycman
Цитата(dxp @ Nov 28 2009, 13:39) *
Код
static const uint32_t X_SIZE = 320;
static const uint32_t Y_SIZE = 240;

Зачем такой "огород" с константами и статиками?
Только лишь для того, чтобы автоматически задавать размерность?
Но ведь всё равно при оперировании с любыми константами операнды должны иметь правильную размерность, иначе переполнения и ошибки не избежать.

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

У меня и так его (оверхеда) нет и без статиков, бо С++. smile.gif И указывать суффикс UL тоже излише. Тип и так четко и однозначно указан.

Цитата(Злодей @ Nov 29 2009, 02:57) *
Код
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: На случай, если они перестанут быть константными или поучаствуют ещё-где-нибудь.

Можно объявить const uint8_t Y_SIZE = 240;. На дальнейшее использование это не повлияет - в использующем выражении операнды все равно будут приведены к нужному типу.


Цитата(sonycman @ Nov 29 2009, 15:26) *
Как правило, все константы задаются просто через дефайны:
Код
#define X_SIZE 320ul

Задавались. А нынче рулят константы. И нет ни одной причины использовать тут макросы. Зато причин не использовать предостаточно.
baralgin
dxp Хм, а если С без плюсов?. Статический массив как бы не объявляется в таком случае.
sigmaN
Ну по-моему бе плюсов там идёт глобальная линковка по умолчанию, а в плюсах наоборот статик подразумевается...если я ничего не путаю.....
baralgin
sigmaN Скорее всего моя терминология хромает, я имею ввиду элеметарную ситуацию:
Код
const int x_size = 10;
int x_mas[x_size];
В Си не соберётся.
sigmaN
аа, об этом я уже как-то упоминал.
Не собирается(как мне объяснили) потому, что объявление и инициализация - это разные этапы компиляции. Т.е. на момент первого прохода компилятор ещё ничего не знает о том, что x_size == 10. Выходом из этой ситуации может быть enum или #define

Как там с подобными конструкциями в плюсах - не знаю....может там и соберется.

Цитата
Скорее всего моя терминология хромает, я имею ввиду элеметарную ситуацию:
да нет, скорее всего я просто Вас неправильно понял и дал ответ на совершенно иной вопрос smile.gif

тут найдете много чего полезного http://electronix.ru/forum/index.php?showtopic=68225
dxp
Цитата(baralgin @ Nov 29 2009, 23:21) *
dxp Хм, а если С без плюсов?. Статический массив как бы не объявляется в таком случае.

Не понял вопроса. Если на С и хочется, чтобы в память не легло, то надо объявлять как static. При этом если нет попыток взятия адреса, то и причин у компилятора заводить под это память не будет - все значения он сможет вычислить на этапе компиляции.
baralgin
dxp в привидённом выше примере static не спасает. Я обычно все глобальные переменные static'ом обзываю (от греха подальше). Ну да ладно, читаю вышерекомендованную тему, делаю выводы. Тут это всё же офтоп.
demiurg_spb
Цитата(baralgin @ Nov 30 2009, 11:29) *
Я обычно все глобальные переменные static'ом обзываю (от греха подальше).
Вы имеете ввиду глобальные константы? Ибо переменная в модуле становится локальной... Ну и все подряд константы делать статическими тоже неверно...


Цитата(dxp @ Nov 29 2009, 18:13) *
У меня и так его (оверхеда) нет и без статиков, бо С++. smile.gif
Ну так а тожsmile.gif
Цитата
Можно объявить const uint8_t Y_SIZE = 240;
На дальнейшее использование это не повлияет - в использующем выражении операнды все равно будут приведены к нужному типу.
Ещё как повлияет, если в int не впишется...
Цитата
Задавались. А нынче рулят константы. И нет ни одной причины использовать тут макросы. Зато причин не использовать предостаточно.
+1
baralgin
Цитата(demiurg_spb @ Dec 1 2009, 08:47) *
Вы имеете ввиду глобальные константы? Ибо переменная в модуле становится локальной... Ну и все подряд константы делать статическими тоже неверно...

Не, я имел ввиду переменные и локальность это только плюс(практически плюсплюс smile.gif ). Const'антами пользуюсь пока крайне умеренно. Тут больше вопрос не "что использовать define или const", а "Си или С++".
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.