LINUX.ORG.RU

[C99] int, int_fast16_t


0

1

Существует ли платформа (процессор, компилятор), где размеры переменных этих типов различаются? Если да, то какая платформа и какие размеры?

UPD: Перед тем как отвечать, перечитайте вопрос не менее двух раз. Если вы его не поняли (у меня плохо с конвертацией мыслей в текст), то лучше вообще не отвечайте. Спасибо.



Последнее исправление: toady2 (всего исправлений: 5)

Ответ на: комментарий от toady2

>А int_fast16_t?

Наверное, тоже 16-битный, но я не пробовал. У меня, ЕМНИП, под досом не стоит сейчас borland c++, только borland pascal по приколу ставил.

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

Нет, я этой штукой только пару раз баловался.

Она вообще-то по-старше чем С99, причём сильно.

Begemoth ★★★★★
()
Ответ на: комментарий от gentoo_root

Наверное, тоже 16-битный, но я не пробовал.

Ппц. Но вы бы хотя бы ради приличия читали вопрос темы.

toady2
() автор топика
Ответ на: комментарий от toady2

>Но вы бы хотя бы ради приличия читали вопрос темы.

Сорри, неправильно распарсил вопрос. Думал, что «на какой платформе int не 32-битный?».

gentoo_root ★★★★★
()
$ cpp -m64 -dM -std=c99 /dev/null | grep -P '__INT(_FAST16)?_(MAX|TYPE)__'
#define __INT_FAST16_TYPE__ long int
#define __INT_FAST16_MAX__ 9223372036854775807L
#define __INT_MAX__ 2147483647
$ _
arsi ★★★★★
()
Ответ на: комментарий от arsi

Спасибо.

То есть 64-битные x86 обращаются с 64-битными регистрами быстрее, чем с их 32-битными половинками?

toady2
() автор топика
Ответ на: комментарий от toady2

> То есть 64-битные x86 обращаются с 64-битными регистрами быстрее, чем с их 32-битными половинками?

в х86_64 вообще может не быть [некоторых] инструкций для работы с половинками, поэтому потребуется кастинг к полному слову перед использованием. кроме того, половинки в агрументах и результатах функций приводятся к полным словам (а потом обратно, да). и это, кстати, не только в х86:

$ /opt/sgpp/bin/powerpc-linux-gnu-cpp -m64 -dM -std=c99 /dev/null | grep -P '__INT(_FAST16)?_(MAX|TYPE)__'
#define __INT_FAST16_TYPE__ long int
#define __INT_FAST16_MAX__ 9223372036854775807L
#define __INT_MAX__ 2147483647
$ _

хотя:

$ /opt/sgpp/bin/mips-linux-gnu-cpp -mips64 -dM -std=c99 /dev/null | grep -P '__INT(_FAST16)?_(MAX|TYPE)__'
#define __INT_FAST16_TYPE__ int
#define __INT_FAST16_MAX__ 2147483647
#define __INT_MAX__ 2147483647
$ _

кросс-компиляторов для других платформ у меня нету…

arsi ★★★★★
()

в х86_64 вообще может не быть [некоторых] инструкций для работы с половинками, поэтому потребуется кастинг к полному слову перед использованием. кроме того, половинки в агрументах и результатах функций приводятся к полным словам (а потом обратно, да). и это, кстати, не только в х86:

Ясно. Спасибо. Но тогда мне не понятно, почему на x86_64 размер int всего 32-бита?

Вопрос темы родился из-за непонимания, в чём вообще отличие int от int_fast16_t (аналогично с другими базовыми типами и int_fast<N>_t). Про int C99 пишет (6.2.5.5)

A ‘‘plain’’ int object has the natural size suggested by the
 architecture of the execution environment (large enough to contain any value in the range
 INT_MIN to INT_MAX as defined in the header <limits.h>).
 
При этом С99 оговаривает, что INT_MIN должен быть не более -2147483647, а INT_MAX не менее 2147483647 (т. е. int должен быть не менее чем 16-битный).

Про int_fast16_t C99 пишет (7.18.1.3):

The typedef name int_fastN_t designates the fastest signed integer type with a width
 of at least N
 

Не вижу разницы. Ткните пальцем, пожалуйста.

toady2
() автор топика
Ответ на: комментарий от toady2

> Не вижу разницы. Ткните пальцем, пожалуйста.

разница в том, что для int не сказано «fastest signed integer type with a width of at least 16 bit» :) а остальным требованиям 32-битный инт соответствует. кроме того, должен же быть какой-нибудь тип 32-битным ;)

arsi ★★★★★
()
Ответ на: комментарий от arsi

разница в том, что для int не сказано «fastest signed integer type with a width of at least 16 bit»

Следует сначала понять, что имел в виду стандарт под «natural size». Лично я это и понял как «наиболее быстрый»; то есть int — базовый тип, работа процессора с которым проста, естественна и быстра. Но я понимаю не верно. Вот почему, скажем, на x86_64 «natural size» равен 32 битам?

кроме того, должен же быть какой-нибудь тип 32-битным ;)

Для таких случаев С99 предоставляет u?int_(8|16|32|64)_t. Только, правда, не понимаю, зачем это вообще нужно. Программиста должно волновать лишь только, чтобы в переменную поместились все значения, которые предполагается в неё хранить; а то, какого размера будет типа на конкретной платформе в конкретной реализации — уже дело компилятора. Да и само использование типа (к примеру) uint32_t портит переносимость (одно из главных фичей Си): я видел контроллеры, у которых байт 9битный. И как из них склеить 32? Ну ладно, оффтоплю. Не буду эту тему развивать...

toady2
() автор топика
Ответ на: комментарий от toady2

> Следует сначала понять, что имел в виду стандарт под «natural size». Лично я это и понял как «наиболее быстрый»

там после слов «natural size» есть ещё: «… suggested by the architecture of the execution environment…».

а «execution environment» (в HOSTED режиме) состоит не только из процессора, но и из ОС, библиотек и т.п, объеденённых некоторым [своим] стандартом. в данном случае — позикс…

к ознакомлению: http://www.unix.org/whitepapers/64bit.html. особое внимание следует уделить фрагменту «In 1995, a number of major UNIX vendors agreed to standardize on the LP64 data model for a number of reasons…».

arsi ★★★★★
()
Ответ на: комментарий от toady2

> Не вижу разницы. Ткните пальцем, пожалуйста.

int_fast16_t не обязан быть natural size suggested by the architecture of the execution environment

Ну и наоборот. Это ортогональные понятия.

LamerOk ★★★★★
()

fast типы, на мой взгляд - извращение. Если вы работаете с массивом, то размер кэша вас должен гораздо больше волновать, чем скорость арифметических операций. Если вы работаете с фиксированным числом переменных, то оставьте эту проблему компилятору.

crimson_eyes
()

Ладно. Задам резюмирующий вопрос. Вот я пишу (переносимую) программу на Сях (С99) и вот мне понадабилась целая переменная, в которой я предполагаю хранить значения, скажем, от -2^30 до 2^30. Будем считать, что эта переменная не имеет узкого назначения: она будет далее использоваться часто и по разному поводу. Какой тип лучшее всего для неё выбрать: int, int_least16_t, int_fast16_t?...

P.S.
1. Пожалуйста, сопровождайте свой ответ содержательными аргументами. 2. Не надо придираться к тому, что на С99 действительно портируемую программу написать сложно, ибо мало компиляторов его поддерживают.
Будем придерживаться утопической точки зрения: все архитектуры, на которые я планирую переносить программу, имеют С99-совместимый компилятор.
3. int — лишь примера. Я надеюсь, вы поняли суть вопроса. Если нет, лучше не отвечайте.

toady2
() автор топика
Ответ на: комментарий от toady2

> от -2^30 до 2^30 Какой тип лучшее всего для неё выбрать: int, int_least16_t, int_fast16_t?

16 бит точно не хватит же. Положим, имелось в виду 32.

31 бита тоже не хватит, значит, надо таки 32. Не вижу поводов не юзать int32_t: он обязан быть по стандарту.

Если будет нужно, например, 48-битное число, то можно юзать int_least64_t: он обязан поддерживаться, в том время как int64_t - нет (ох и проказники эти авторы стандартов). Можно проверить, не поддерживается ли вдруг int_least48_t.

const86 ★★★★★
()
Ответ на: комментарий от crimson_eyes

> fast типы, на мой взгляд - извращение. Если вы работаете с массивом, то размер кэша вас должен гораздо больше волновать, чем скорость арифметических операций.

А кто тебе сказал, что fast типы определяются именно скоростью арифметический операций и ничем другим?

LamerOk ★★★★★
()
Ответ на: комментарий от const86

> Не вижу поводов не юзать int32_t: он обязан быть по стандарту.

о_О
О_о
О_________О

цитату из стандарта, срочно.

arsi ★★★★★
()
Ответ на: комментарий от const86

См. п.3 P.S.

Конечно же, я всё напутал. Скажу проще: моя переменная нуждается минимум в 16 битах. Далее по тексту.

toady2
() автор топика
Ответ на: комментарий от toady2

> Скажу проще: моя переменная нуждается минимум в 16 битах. Далее по тексту.

Ну и все мои слова про 32-битные числа походят и к 16-битным.

const86 ★★★★★
()
Ответ на: комментарий от const86

> Спокуха. Смотри man stdint.h, раздел про Exact-width integer types.

сам смотри:

7.18.1.1 Exact-width integer types
(3) These types are optional. …

const86> Не вижу поводов не юзать int32_t: он обязан быть по стандарту.

ня?

arsi ★★★★★
()
Ответ на: комментарий от arsi

> ня?

Так мы о разном :) Я наивно смотрел SUSv4, который базируется на C99, но требует больше. Хорошо, если интересно именно C99, то имеет смысл использовать int_leastN_t. Локальные переменные можно делать int_fastN_t, но это уже из разряда хитрый оптимизаций не на каждый день.

const86 ★★★★★
()
Ответ на: комментарий от const86

Хорошо, если интересно именно C99, то имеет смысл использовать int_leastN_t. Локальные переменные можно делать int_fastN_t, но это уже из разряда хитрый оптимизаций не на каждый день.

См. п.1 P.S.

toady2
() автор топика
Ответ на: комментарий от toady2

> См. п.1 P.S.

Аргументы на поверхности: least не больше, чем fast. Жрать место в структурах, куче и стеке почём зря - негоже.

const86 ★★★★★
()
Ответ на: комментарий от toady2

> Будем считать, что эта переменная не имеет узкого назначения: она будет далее использоваться часто и по разному поводу. Какой тип лучшее всего для неё выбрать: int, int_least16_t, int_fast16_t?...

для многих систем — точно не int: его разрядность обусловлена традициями, а не эффективностью. int_least16_t предназначен в первую очередь для больших массивов, а не для одиночных переменных. для локальных переменных или небольших массивов — int_fast16_t. ещё для размышлений могу репостить параграф из книги «ARM System Developer’s Guide: Designing and Optimizing System Software», раздел «Efficient C Programming» — «Basic C Data Types»:

ARMv4-based processors can efficiently load and store 8-, 16-, and 32-bit data. However, most ARM data processing operations are 32-bit only. For this reason, you should use a 32-bit datatype, int or long, for local variables wherever possible. Avoid using char and short as local variable types, even if you are manipulating an 8- or 16-bit value. The one exception is when you want wrap-around to occur. If you require modulo arithmetic of the form 255 + 1 = 0, then use the char type.

совет подходит и для других архитертур кроме арма.

arsi ★★★★★
()
Ответ на: комментарий от arsi

совет подходит и для других архитертур кроме арма.

А если я о целевой архитектуре ничего не знаю? (Её разрядность и особенности процессора тоже.) Ведь действительно кроссплатформенный язык должен это предполагать. Я написал код для i386, другой скомпилил для ARM, а третий для какого-то TMS от Texas Instruments с 32-разрядным байтом. По идее меня это вообще не должно заботить. *Низкоуровневая* оптимизация — дело компилятора. (Высокоуровневая (используемый алгоритм и пр.) — уже дело программиста.) Я пишу, что мне нужно для переменной хотя бы 12 бит. Компилятор должен на каждой архитектуре выбрать наиболее подходящий для меня вариант.

Или я не так себе представляю кроссплатформенность Си?

toady2
() автор топика
Ответ на: комментарий от toady2

P.S. Есть ли какие-нибудь официальные (и не очень) рекомендации по написанию хорошего портируемого кода на Сях?

toady2
() автор топика
Ответ на: комментарий от toady2

> А если я о целевой архитектуре ничего не знаю?

вот для таких случаев и ввели типы /u?int_(least|fast)\d+_t/ ;)

arsi ★★★★★
()
Ответ на: комментарий от toady2

>А если я о целевой архитектуре ничего не знаю?

Тогда ты не имеешь права под нее писать на Си.
И за попытки такого тебе надо отрубать руки.

Си - очень низкоуровневый язык, и никаким образом не кроссплатформенный.

Как возьмешься за реальную задачу, сам это поймешь.

anonymous
()
Ответ на: комментарий от toady2

> А если я о целевой архитектуре ничего не знаю?

Тогда тебе не надо писать на С. Для написания программ на С, кроме размеров int'а надо еще знать объём доступной памяти, размер стека, доступную подсистему ввода-вывода и т.д.

Если, конечно, ты действительно хочешь написать реальную программу, исполняемую в какой-либо вычислительной среде.

Ведь действительно кроссплатформенный язык должен это предполагать.

Ты не путай язык со средой выполнения. Язык может быть «кроссплатформенным» сколько угодно, но реальные программы, а не абстрактные алгоритмы работают только в реальной аппаратно/программной среде выполнения (пусть и в виртуальной машине :3).

И запомни, уже, наконец, нет никакой «кроссплатформенности» - это маркетинговый миф для засира мозгов школоте. Есть только переносимость и совместимость.

LamerOk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.