LINUX.ORG.RU

char это и не signed и не unsigned а непонятно что

 


3

6
> cat main.cpp
#include <type_traits>

int main() {
        static_assert((::std::is_same<char, signed char>::value) == true);
        static_assert((::std::is_same<char, unsigned char>::value) == true);

        return 0;
}

> g++ -Wall -Wextra main.cpp
main.cpp: In function 'int main()':
main.cpp:4:2: error: static assertion failed
  static_assert((::std::is_same<char, signed char>::value) == true);
  ^~~~~~~~~~~~~
main.cpp:5:2: error: static assertion failed
  static_assert((::std::is_same<char, unsigned char>::value) == true);
  ^~~~~~~~~~~~~
★★★★

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

Писать холодный код на си особого смысла не имеет

Сильное утверждение. Или у нас терминология существенно различается.

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

Писать холодный код на си особого смысла не имеет

Сильное утверждение. Или у нас терминология существенно различается.

Сишка, как близкий к железу язык, должна использоваться в местах, где эта близость к железу существенна. Например, какой-нибудь тяжёлый лупчик, который часто/долго оккупирует процессор. Вот такой код я и называю горячим.

Холодным я называю код, оптимизации в котором существенно не влияют на overall performance. Личный опыт состоит в том, что такой код можно писать на питоне, ну и потом приклеить сишную часть через FFI. Я не говорю, что это возможно сделать во всех случаях... Но связка (ЯП высокого уровня) + (тяжелые части на сях) довольно популярна, и не просто так.

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

Например, какой-нибудь тяжёлый лупчик, который часто/долго оккупирует процессор. Вот такой код я и называю горячим.

Хех. Мы доходим до того что гоняем «холостые» events чтобы держать CPU cache hot…

Личный опыт состоит в том, что такой код можно писать на питоне

Подозреваю что речь идёт о числодробилках (batch kind of jobs).

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

Подозреваю что речь идёт о числодробилках (batch kind of jobs)

Ага. Но, imho, даже в остальных случаях на си per se писать не нужно, если доступен си++. То есть, самые горячие места пишем в сишном стиле (потому что он близок к железу), которые обвязываем уже высокоуровневыми примочками языка си++ (классы, шаблоны, итераторы, you name it).

То есть предлагаю такую схему. Если заранее понятно, что FFI неплохо налезет, то его и брать. Если ожидается, что сам интероп будет занимать существенное время, то берём си++ и пишем на нём, опускаясь до сишного байто*бства там, где требуется. Если си++ никак не берётся, то вздыхаем и пишем всю программу на си... Короче, для меня это fallback option.

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

на си per se писать не нужно, если доступен си++.

В этом контексте - я разницы не делаю. Собственно на голом “C” я не писал лет N-дцать как.

Если заранее понятно

Знал бы прикуп - жил бы в Сочи, что называется. Мы немножко в разных мирах существуем: я за latency гоняюсь, и поверьте - очень далеко готов зайти чтобы порвать конкурентов.

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

и поверьте - очень далеко готов зайти чтобы порвать конкурентов.

Рыбак рыбака узнает издалека..

Мы немножко в разных мирах существуем: я за latency гоняюсь

HFT, если я правильно понимаю? Для меня это действительно незнакомый мир. В некотором[1] смысле даже противоположный моему миру HPC...
Тем забавнее, что из обоих этих миров домов товарищу хрюнделю идёт один и тот же месседж:

Использование размеров отличных от register size для temporaries - преступление за которое в приличных домах больно бьют по рукам

Надеюсь, он всё-таки сможет его услышать!

[1] У нас оптимизируют интегральное время расчёта, а у вас отзывчивость системы, что есть дифференциальная характеристика.

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

Рыбак рыбака узнает издалека..

А то ж :) По моей информации Вы же с ФУПМ? 13-я группа здесь. Предполагалось что я чипы дизайнить буду, но получилось то что получилось. Но тем не менее - понимание как оно устроено очень помогает в написании софта. Осталось только разобраться «как устроен этот мир» in general, но это в процессе ;)

HFT, если я правильно понимаю?

Есть чутка ;)

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

То, что ты назвал «для криптографической либы», я бы назвал адекватным подходом к разработке софта.

Нет, дурак, ты просто не знаешь как делается большая арифметика. Но тебе и не нужно, главное понимать, что если тебе надо перемножать 2048 бит, то лучше это делать разбивая на куски по 16 чем на куски по 8. Рост производительности тут идёт от задачи, ей надо эти 2048 бит перемножать. Сложность умножения в столбик - N в квадрате, где N - число кусков на которые ты большое число поделил. Более хитрые алгоритмы дают вроде бы N*log(N), хотя тут могу соврать. В любом случае, конкретно в криптографии использование в 2 раза более широкой операции уменьшит время выполнения в 2 с лишним раза. Тут смысл действительно есть.

В прикладном коде тебе надо перемножать 52*78 и если ты, зная что числа ограничены 100 и их произведение, соответственно, 10 тысячами, заявишь компилятору, что тебе нужно 2 ярда, то никакой эффективности ты не получишь.

Эффективность здесь определяется через утилизацию процессорных блоков

Я вижу ты уже понял что обосрался и решил прикинуться дурачком-эстетом, для которого важно «загрузить блок полностью». Однако ранее ты пел иное, цитирую: «Проблема в падении перфа. Если есть умножитель, который умеет умножать два 32-битных числа, то не надо в него умножения 16-битных пихать.»

Что случилось?

Про загрузку всех блоков тебе уже объяснили. Да, внезапно, возможны 2 случая. В одном, самом простом и самом тупом, 16битыве операнды будут складываться на 64битном сумматоре и разницы не будет никакой. В другом возможны варианты. Причем заметь, железо ведь тоже разрабатывают не в вакууме. Если бы программисты чаще использовали типы с меньшей разрядностью, разве не догадались бы разработчики процессоров сделать возможность выполнять несколько малоразрядных операций на одном АЛУ? Вон, в GPU вполне себе умеют обрабатывать 16битные флоаты с двойной скоростью.

Кстати, такой ещё к тебе лично вопрос. Вот у нас уже K8, Core 2 и пентиум 4 отправлены в отставку. На них даже винду не установить современную. Так, так что умножение 64 бит выполняется с той же скоростью, что и умножение 8 бит. Да и до этого, там разница была типа 4 такта латентности против 3х, не бог весть что. По твоей логике, раз полная ширина АЛУ - 64бита, то и инт должен стать 64битным. А его до сих пор 32битным держат. Где твое возмущение? Что за предатели окопались среди разрабов компиляторов?

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

Я вижу ты уже понял что обосрался и решил прикинуться дурачком-эстетом, для которого важно «загрузить блок полностью»

Извините, просто это моя специальность. Мне буквально платят деньги за то, что я «загружаю блоки полностью». На остальные ваши сообщения отвечать желания уже не имею. Всего хорошего.

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

По моей информации Вы же с ФУПМ

Был когда-то... Но HPC меня учил товарищ Келдыш. В «сильную» группу по информатике на ФУПМе мне попасть не удалось, так как со школы я знал только паскаль, и то средне

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

Ага. Только если значащих бит N1 < N, то эффективность утилизации сумматора падает. До величины N1/N

Я тут на работу пришёл. Рискую хохотом обрушить офисное здание.

Мальчик, ты понимаешь словосочетание «аппаратный сумматор». Это такой «кубик» в процессоре, у которого вход А 32 битный и вход В 32-битный. Как ты на него собираешься подавать 16- или 8-битные данные?

akk ★★★★★
()
Последнее исправление: akk (всего исправлений: 1)
Ответ на: комментарий от akk

Дядя, я вообще не буду подавать в 32-битный сумматор 16-битные и 8-битные данные. Чего и вам желаю.

Crocodoom ★★★★★
()

Я вот читаю срач и складывается ощущение, что нативные С-шные типы (вроде short, int и long) защищают те немногие счастливчики, которым повезло:

  • писать софт под конкретную платформу, для которой они точно знают размерности и представление этих самых short, int и long;
  • заниматься низкоуровневой оптимизацией, которая заставляет их знать во что обходится работа с этими самыми short/int/long на конкретной аппаратной платформе;

плюс, по всей видимости, у них есть роскошь не думать о том, а что будет с написанными ими кодом лет через 15-20-30.

Грубо говоря, эти счастливчики имеют возможность писать в коде int и точно знать, что это, например, 32-й битовый тип. Или 64-й битовый. Но уж никак не 16-ти или 24-х.

Между тем, есть и другие разработчики, которые, скажем, пишут повторно используемые библиотеки. Или какой-нибудь middleware, основными требованием к которому является переносимость.

И вот у этих разработчиков нативные типы short/int/long, мягко говоря, вызывают ненужные вопросы. Например, если мне нужно работать со значениями в диапазоне от -250’000 до +250’000, то какой тип мне задействовать?

Может быть int?

А где гарантия, что это поместиться в int?

На 16-ти битах, вообще-то говоря, не поместится.

Можно, конечно, сказать, что кого в XXI-ом веке волнуют 16-битовые системы. Можно. Но, как мне кажется, здесь уже начинается некоторое лукавство, т.к. мы начинаем ограничивать понятие «переносимость».

Или, скажем, мне нужно работать с большим количеством мелких объектов. И для того, чтобы эти объекты были мелкими и я мог держать их размер под контролем, мне нужно понимать, сколько какой тип занимает в памяти. Опять же, с учетом того, что должно поместиться в значение этого типа.

Посему получается, что для решения реальных задач (а не примерчиков из категории hello_world) разработчик должен знать о размерностях применяемых им целочисленных типов. И, более того, это знание крайне желательно выражать непосредственно в коде. Т.е. вместо int использовать int16_t/int_least16_t или int32_t/int_least32_t.

И даже когда нам требуется работать с нативными целочисленными типами конкретной архитектуры (для выжимания всех тактов из битов), то вместо int/long хорошо было бы иметь какой-нибудь __int32_t/__int64_t или native_int32_t/native_int64_t. Хотя бы для того, чтобы в коде явным образом зафиксировать привязку к типам конкретного CPU.

А раз так, то логичным выглядит иметь в языке набор типов с явно определенными размерностями для случаев когда нам нужны гарантии того, что

  1. Тип содержит минимально-необходимое количество бит (как int_least16_t, int_least32_t и т.д.). Для случая, когда нам нужна максимальная портабельность пусть даже ценой производительности;
  2. Тип содержит жестко заданное количество бит (как int16_t, int32_t и т.д.). Для случая, когда нам нужны иметь гарантии представления значения в памяти (во внешней, в первую очередь, ИМХО). С отсутствием каких-то их этих типов, если они не представимы на конкретной платформе (скажем, нет int16_t и int64_t там, где все только через 32-х битовые значения работает);
  3. Тип содержит заданное количество бит и имеет конкретную стоимость обработки на конкретной архитектуре. Типа native_int16_t, native_int32_t, native_int64_t. С потенциально возможными native_int24_t или native_int48_t для каких-то экзотических случаев. И с отсутствием каких-то типов, если они не представимы на конкретной платформе (т.е. там, где есть только native_int32_t не будет native_int16_t и native_int64_t).

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

Но, в этом же случае, родные С-шные short/int/long оказываются бесполезными.

ЗЫ. Полезность int_fast16_t/int_fast32_t/int_fast64_t, КМК, зависит от ряда факторов. Например, если для конкретной программы важно знать, насколько эффективно представляется в памяти (передается по шинам) 32-х битовое значение, то тип int_fast32_t может и не подойти, т.к. никто не гарантирует, что это не будет 64-х или даже 128-ми битовое значение.

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

Дельный пост.
Но главную идею можно описать короче. Когда нужно упаковать данные в памяти, используйте типы с фиксированной разрядностью. Когда вы работаете с данными, используйте алиасы с плавающей разрядностью.

bugfixer уже писал про это, а я лишь раскрывал его мысль со своей HPC-колокольни:

Использование shorts полезно только если оно позволяет сэкономить на memory bandwidth. Ну, если совсем на пальцах - пробежаться по int16_t[1000000] будет ровно в 2 раза быстрее чем по int32_t[1000000]. Использование размеров отличных от register size для temporaries - преступление за которое в приличных домах больно бьют по рукам (и не только). Погуглите «partial register stall». Не благодарите.

Вы:

Полезность int_fast16_t/int_fast32_t/int_fast64_t, КМК, зависит от ряда факторов. Например, если для конкретной программы важно знать, насколько эффективно представляется в памяти (передается по шинам) 32-х битовое значение, то тип int_fast32_t может и не подойти, т.к. никто не гарантирует, что это не будет 64-х или даже 128-ми битовое значение.

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

Когда вы работаете с данными, используйте алиасы с плавающей разрядностью.

Что такое «алиасы с плавающей разрядностью»?

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

Не понятно, где там плавающая разрядность. Как по мне, так плавающая разрядность она у int-а или у long-а, когда она легально может быть 16 или 32 (или 32/64). В случае же с алисами из cstdint минимальный верхний порог как раз таки гарантирован.

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

В случае же с алисами из cstdint минимальный верхний порог как раз таки гарантирован.

Верхний или нижний? По-моему вы уже сами запутались

Тип int_fast16_t гарантирует, что 16-битные числа туда влезут. При этом сам он может быть 32-битным. Ну прям как int

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

Верхний или нижний?

Верхний порог. В том плане, что int_least16_t говорит о том, что верхний порог, которым пользователь может гарантированно безопасно пользоваться – это 16 бит. Может быть и больше, но толку от этого для пользователя нет, т.к. эта возможность не гарантирована.

Тогда как ниже 16 быть не может, т.е. ниже 16 бит этот тип не опустится.

В этом смысле термин «нижний» не имеет смысла, имхо, т.к. то, что «выше» использовать нельзя.

При этом сам он может быть 32-битным. Ну прям как int

Это будет иметь значение только если для пользователя важно знать как int_fast16_t отображается в память (размер, выравнивание). Но эти знания как раз должны превращать int_fast16_t в конкретный native_int16_t или native_int32_t, или во что-то еще.

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

В этом смысле термин «нижний» не имеет смысла, имхо, т.к. то, что «выше» использовать нельзя.

Почему нельзя то? Это же просто тайпдефы (синонимы типов)

/* Fast types.  */

/* Signed.  */
typedef signed char   int_fast8_t;
#if __WORDSIZE == 64
typedef long int    int_fast16_t;
typedef long int    int_fast32_t;
typedef long int    int_fast64_t;
#else
typedef int     int_fast16_t;
typedef int     int_fast32_t;
__extension__
typedef long long int   int_fast64_t;
#endif
Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Я могу взять чужой код, который использует int_fast16_t, убедиться в том, что на моей платформе это typedef long int и передать туда long int. Сломаться ничего не должно

Crocodoom ★★★★★
()
Последнее исправление: Crocodoom (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

Почему нельзя то?

На такой вопрос остается только ответить «по качану».

Я могу взять чужой код, который использует int_fast16_t, убедиться в том, что на моей платформе это typedef long int и передать туда long int. Сломаться ничего не должно

На конкретной платформе с конкретным компилятором и конкретной реализацией stdlib – не должно.

Только вот непереносимо это будет.

Отсюда смотрим то, что я писал выше: есть те, кто пишет код, заточенный под то, что есть здесь и сейчас. А есть те, кто лишен такой роскоши. Ну или просто лично проходил путь перехода с 16bit на 32bit, а затем и на 64bit. И не хочет больше ходить по этим граблям.

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

есть те, кто пишет код, заточенный под то, что есть здесь и сейчас

Такие есть

А есть те, кто лишен такой роскоши.

И такие есть

Панчлайн! И чтобы первые могли переиспользовать код вторых, для вторых сделали эти самые int_fast16_t, int_least16_t. А первые могут использовать какие угодно типы, конечно же.

По-крайней мере именно так я вижу логику эти синонимов. А как видите её вы? Или, по-вашему, комитет [1] добавил их совершенно зря?

[1] Готов принять вашу точку зрения, если она будет обоснована. Лишнего пиетета ни перед вами, ни перед комитетом не испытваю.

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

И чтобы первые могли переиспользовать код вторых

Проблема не в этом.

Проблема в том, что вторые не смогут переиспользовать код первых.

При этом в данной ветке первые доказывают надобность именно что С-шных short/int/long, хотя вторым как раз этим самые short/int/long не нужны.

И, лично мне кажется, что время показало бесполезность short/int/long. По крайней мере с позиции написания портабельного кода.

А как видите её вы?

Я не очень понимаю, зачем нужны одновременно и least-типы, и fast-типы. Как по мне, так логика есть в случае, когда у нас есть:

  • опциональные fixed-size типы, которых на конкретной платформе может и не быть;
  • least-типы, которые гарантированно есть, но эффективность которых нам не важна;
  • какие-то нативные fixed-size типы, набор которых на разных платформах может отличаться.

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

Насколько полезна эта эффективность в отрыве от специфических возможностей конкретного железа мне не ведомо, т.к. HPC не занимался.

Остается надеяться, что в комитете люди поопытнее меня сидели и в данном случае они не ошиблись.

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

Я пишу в основном платформо-зависимый код, а когда мне нужна полиморфность, стараюсь достигать её средствами C++; ну хотя бы тем же шаблонами (+ специализация)

По stdint.h лучше консультироваться таки с матёрыми сишниками... Помогают им эти uint_fast16_t, uint_least16_t в проде или же это бесполезная цацка

Crocodoom ★★★★★
()
Последнее исправление: Crocodoom (всего исправлений: 1)
Ответ на: комментарий от eao197

При этом в данной ветке первые доказывают надобность именно что С-шных short/int/long

Первые доказывают, что short, int, long - это и есть int_least16_t, int_least16_t, int_least32_t, первые объясняли суть нефиксированности размера типов. Я даже показал даташит на одну специфическую архитектуру.

При этом никто не спорил, что для переносимости лучше сделать typedef’ы на int_least… . short, int, long лучше оставить для локальных hello world’ов под конкретную data model.

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

Первые доказывают, что short, int, long - это и есть int_least16_t, int_least16_t, int_least32_t

Да что вы говорите!

Вот, int, например, может ли считаться синонимом для int_least32_t?

А long может ли считаться синонимом для int_least64_t?

первые объясняли суть нефиксированности размера типов

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

short, int, long лучше оставить для локальных hello world’ов под конкретную data model.

Т.е., по факту, лучше бы их выставить на мороз.

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

Вот, int, например, может ли считаться синонимом для int_least32_t? А long может ли считаться синонимом для int_least64_t?

Прям точным аналогом - нет, но также дают гарантии:

short - int_least16_t
int - int_least16_t
long - int_least32_t
long long - int_least64_t

А суть в том, что эта нефиксированность только ведет к лишним проблемам.

Это ведёт к возможности пистать переносимо без необходимости держать форк с правками под каждую железку. В общем я не хочу по второму кругу, я все аргументы уже сказал.

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Прям точным аналогом - нет, но также дают гарантии:

Т.е. если мне нужно иметь гарантии, то проще послать int/long лесом и взять int_least32_t/int_least64_t.

ЧТД.

Это ведёт возможность пистать переносимо

Полагаю, «переносимо» здесь будет иметь ряд ограничений. Типа переносимо между 32-х и 64-х битовыми платформами.

Потому что мне сложно представить, как без дополнительных приседаний перенести код с 32-х битовыми int-ами на 16 бит. Или на условные 24.

Не, наверное, если в этих int-ах хранятся значения типа -1 или 0, то без проблем. Но вот если int используется для хранения значений из некого диапазона (скажем от -1’000’000’000 до 1’000’000’000) или unsigned int использует 29 бит из 32-х возможных для битовых флагов, то тогда как-то все печальнее.

В общем я не хочу по второму кругу, я все аргументы уже сказал.

Проблема аргументов в защиту short/int/long в том, что эти аргументы, походу, убеждают только тех, кто эти самые аргументы и приводит.

Для менее ангажированных читателей ситуация не так очевидна.

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

Т.е. если мне нужно иметь гарантии, то проще послать int/long лесом и взять int_least32_t/int_least64_t.

Мы что-то разное доказываем. Я здесь обсуждал саму концепцую «нефиксированные типы», уважаемые доны заявили, что в новомодных языках такого непотребства нет, а в сях караул, я ввязался лишь для донести, что это имеет смысл.

Против int_least32_t/int_least64_t я ничего против не имею, хорошая штука для переносимости, я даже не против фиксированных типов в нужных местах в виде всяких артефактов (файлы и тп).

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

Только вот непереносимо это будет.

Полезность «переносимости» очень сильно overrated, я считаю.

есть те, кто пишет код, заточенный под то, что есть здесь и сейчас.

Наверное больше из области философии, но мне это видится единственным разумным подходом. Всё остальное by definition попадает в категорию «coding for the future».

А есть те, кто лишен такой роскоши.

Я могу поинтересоваться что даёт «лишенцам» повод думать что их код переносим? Как они тестируются? И где границы условной «переносимости» - потенциальные performance regressions туда входят или нет?

Ну или просто лично проходил путь перехода с 16bit на 32bit, а затем и на 64bit. И не хочет больше ходить по этим граблям.

Я не думаю что при нашей жизни это случится ещё хоть раз.

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

Полезность «переносимости» очень сильно overrated, я считаю.

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

Наверное больше из области философии, но мне это видится единственным разумным подходом.

Особенно это ярко проявляется когда фигачим код для x86 с его little-endian, а потом хоба, и нужно на ARM с big-endian, а в коде сплошные манипуляции с расположением байт в памяти.

Я могу поинтересоваться что даёт «лишенцам» повод думать что их код переносим?

Опыт, конечно же. Сын ошибок трудных :)

Как они тестируются?

Почти что точно так же.

потенциальные performance regressions туда входят или нет?

Чтобы оценивать regression нужно сперва получить корректные результаты на новой платформе.

Я не думаю что при нашей жизни это случится ещё хоть раз.

Очень возможно. Но если отталкиваться от этого, то int-ы и long-и, которые могут менять свой размер нужно смело отправлять на свалку истории.

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

Я здесь обсуждал саму концепцую «нефиксированные типы», уважаемые доны заявили, что в новомодных языках такого непотребства нет, а в сях караул, я ввязался лишь для донести, что это имеет смысл.

У меня есть ощущение, что неправы здесь все. И те, кто кивает на новые языки. И те, кто защищает наследие Си-шки.

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

Особенно это ярко проявляется когда фигачим код для x86 с его little-endian, а потом хоба, и нужно на ARM с big-endian, а в коде сплошные манипуляции с расположением байт в памяти.

Не, ну аккуратней надо быть с кросс-платформностью. LE/BE это далеко не самое большое «зло». Даже в пределах x86 можно «отгрести» когда, например, процессы разной битности ходят в одну SHM. А в контексте x86 vs ARM я бы больше за memory ordering переживал - x86 «всепрощающ», а ARM по моей информации куда как более relaxed (в «боевой» обстановке с ARM’ами дела не имел), и вот это вот отлавливать будет намного сложнее чем LE/BE баги, особенно если lock-free / wait-free код имеется.

Чтобы оценивать regression нужно сперва получить корректные результаты на новой платформе.

И вот здесь мы подходим к самому главному - утром деньги, вечером стулья. Сначала мы собираемся и тестируемся на новой платформе, и только потом код декларируется спортированным на конкретную платформу, и никак иначе. А до тех пор можно лишь обсуждать сколько усилий это займет.

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

В подавляющем числе случаев нужен просто int, и это именно то что будет работать наиболее эффективно.

Тут как-то fsb4000 приводил ссылку на тему: How to find the first nonzero in an array efficiently?. В данной теме Rust показывал прирост производительности при использовании u128 вместо u32 (что соответствует сишному uint). fsb4000 с помощью ассемблерной вставки ещё ускорил алгоритм, использовав 256 бит.

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

fsb4000 с помощью ассемблерной вставки ещё ускорил алгоритм, использовав 256 бит.

Довольно красиво сделал (там правда intrinsics а не asm, но это мелочи). Но я не до конца понимаю какое это имеет отношение к моему посылу использовать int а не int8/16/32/64 там где это возможно?

P.S. На самом деле в теме о нахождении первого не-нолика всё очень сильно зависит от входных данных: если мы ожидаем мало leading zeros не факт что банальный лупчик будет медленнее. А если ещё учесть что avx256 имеет тенденцию быть медленным поначалу (почитать можно туточки) то всё становится ещё менее очевидным. В общем - я бы с выводами не спешил, и прежде всего тестировался на нагрузках и данных приближенных к «боевым».

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

Но я не до конца понимаю какое это имеет отношение к моему посылу использовать int а не int8/16/32/64 там где это возможно?

А смысл в чём? Если мы уже привязываемся к конкретному железу (а именно к современным компьютерам), то int32 и int64 не будут менее эффективны, чем int. Или нет?

Пока что единственное преимущество int, которое я вижу - более красивое название типа, если нам не важно количество бит. А что касается прочих long и short, то они уже точно не нужны - нагляднее будет с типы цифрами.

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

А смысл в чём? Если мы уже привязываемся к конкретному железу (а именно к современным компьютерам), то int32 и int64 не будут менее эффективны, чем int. Или нет?

Как мы знаем на x86[-64] int и int32 это одно и тоже. Фундаментальная разница в наиболее точном выражении of intent: каждый раз когда я вижу гвоздями прибитую размерность у меня мгновенно возникает вопрос «а зачем что-то отличное от default человеку понадобилось?». Фиксированные размеры имеют полное право на жизнь там где memory layout важен (структурки живущие в SHM, длинные массивы etc), но если это какой-то temporary (например индекс цикла) - уж лучше ему оставаться обычным int’ом, в худшем случае size_t если переполнение 32bit в конкретном месте реально (но таких по факту немного).

А что касается прочих long и short, то они уже точно не нужны - нагляднее будет с типы цифрами.

Вот здесь - согласен. У нас long вообще забанен так как меняет размер между m32 и m64 - столько проблем с этим отгребли в свое время, что даже не смешно.

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

Извините, просто это моя специальность. Мне буквально платят деньги за то, что я «загружаю блоки полностью».

Платят деньги за то что заменяешь short, int16_t и int32_t на int? Сомневаюсь. Уточни у работодателя.

А вообще, после обсера со сказочками про падение производительности от использования малоразрядных типов, тебе несколько поздновато строить из себя эксперта в оптимизации. Это как если бы защитник телегонии вдруг бы заявил, что он - практикующий врач-генетик. Если врёт - то тупо, а если вдруг не соврал… Ну блин, тогда страшно за индустрию.

На остальные ваши сообщения отвечать желания уже не имею.

А что случилось? Неужели наш эксперт дважды обосравшись таки осознал, что его сила не в конкретике?

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

Проблема в том, что нет у тебя «просто инта». «Просто инт» - это BigInt, целое неограниченной размерности. В нем ты можешь взять перемножить десяток целых чисел, а потом поделить на десяток других и не потерять в точности. То что у тебя есть - это инт ограниченной ширины, но мы тебе не скажем какой.

В этом и ошибка создателей C они не осознавали, видимо, до конца, что делают кроссплатформенный ассемблер, они где-то добавили оператор инкремента, потому что многие платформы его выполняют быстрее, а в другом месте попытались в абстракцию, будучи неспособными ее обеспечить. Да даже из названий этих типов, unsigned long int - это что за срань вообще? Какого лешего имя типа состоит из нескольких слов, одно из которых можно пропускать? Тут явная попытка играть в «естественный язык», которая стоила седых волос разработчикам компиляторов.

Вот, во время игр в абстракцию и запилили тип «целое». 16 бит. Потом, заметив что предел в 32тысячи - это недостаточно для целого увеличили до 32х, там где это недорого. А вот до 64 как-то не стали, типа 2 миллиардов уже достаточно. На основании этого казуса куча народа поверило в существование Великого Правила Нативного Инта, которое правда работает только в промежутке от 16 до 32 бит.

Собственно в истории IT полно эпизодов, когда успешные проекты содержали ошибки. Как технического плана, так и таргетированная. Например Linux и Java изначально планировались для десктопа, а теперь вот широко используются везде кроме десктопов. Так и с C - язык вытеснен из ниши в которой имеет смысл оперировать понятиями «просто целое», а там где остался надо точно знать разрядность. Собственно это уже произошло, int де-факто стал синонимом int32_t. Посмотри например на openCl. Они добавили тип half - 16битный флоат. Потому что железо для которого программируют на openCl умеет оперировать в SIMD с 16битами и делает это быстрее чем с 32. И значит операции типа gather/scatter с 16битными компонентами есть. И 16битный тип short там тоже есть. Вероятно 16битные целые увеличат пропускную способность вдвое. Если не на существующих GPU, то на тех, которые могут появиться. Однако никому в голову не пришло для большей производительности определить int снова 16битным. Так что даже если завтра представят новую 8битную платформу, подозреваю что родной для нее компилятор c будет послушно перемножать столбиком 32битные инты, просто чтоб не подводить ожидания программистов.

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

Проблема в том, что нет у тебя «просто инта».

У меня - есть. И у миллиона остальных «лемингов» - тоже. И что он значит я уже неоднократно писал.

«Просто инт» - это BigInt, целое неограниченной размерности.

Нет. Просто int - это native register size, ни больше, ни меньше. Если кто-то это трактует по другому - это его личные проблемы. Главное чтобы авторы компиляторов от этой трактовки не отходили, но я думаю - в обозримом будущем им и не даст никто.

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

Собственно в истории IT полно эпизодов, когда успешные проекты содержали ошибки.

Не удержался. Вы видели безглючный софт сложнее «hello world»?

Однако никому в голову не пришло для большей производительности определить int снова 16битным.

Я могу себе представить что он подрастёт до 64бит (очень сомнительно, на самом деле), но движения в сторону 16ти не вижу никак.

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

а там где остался надо точно знать разрядность

Ты сам это выдумал, зачем тебе знать точную разрядность в счетчике цикла, например? Точная разрядность нужна редко (запись в файлы, сокеты и тп). В общем тезис выдуман и не доказан.

SIMD

Что тебе это СИМД покоя не даёт? В СИМД регистр сначала данные нужно загрузить, сделать ты это можешь хоть из 100500 битного инта с потерей «хвоста». Нефиксированный размер типов вообще ничего здесь не значит.

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

Ты сам это выдумал, зачем тебе знать точную разрядность в счетчике цикла, например?

Злые языки говорят, что некоторые обломились при переходе на 64-бита вот в таких случаях:

std::vector<char> data;
...
for(int i = 0; i < data.size(); ++i)
  data[i] = ...;

Вруть, наверное.

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

Если некоторые не осилили прочитать, что int гарантирует лишь 16 бит, то это их проблемы. Даже этот код не факт что станет невалиден, возможно там запас с головой. И если бы они заюзали int32, то при переходе они обломились бы точно так же.

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Так мы же про реальный мир, в нем обычные программисты код пишут. Который, не смотря на все невалидности, в текущих условиях работает.

Даже этот код не факт что станет невалиден

Он в принципе невалиден, т.к. вместо int-а нужно было бы vector<char>::size_type использовать. Ну или хотя бы size_t.

И если бы они заюзали int32

Тем не менее, лишняя подсказка в коде.

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

Он в принципе невалиден, т.к. вместо int-а нужно было бы vector::size_type использовать. Ну или хотя бы size_t.

Ну т.е. нефиксированный тип. А фиксированный не менее ущербен в данном кейсе. Значит условный Хрюндель верующий в последние, также получит по лбу граблями.

kvpfs ★★
()

Уважаемые эксперты. Объясните плз мне про int <-> type* взаимоотношения.

Правильно ли я понимаю что type* - type* == ptrdiff_t (соответственно и type* +/- ptrdiff_t == type*)? Который к слову почему то самый маленький из всех. Гарантируют мин 16 бит.

Дальше есть size_t/ssize_t, тип пожирнее. Но роль у него та же - относительная разница указателей в пределах сегмента памяти. Только тут четко байты, когда в ptrdiff_t - мин гранулянтность памяти. К слову есть платформы где к отдельному байту по указателю не обратиться.

И наконец есть опциальный uintptr_t/intptr_t для абсолютных адресов. Применять часто не рекомендуется тк жирный. Максимум пригоден проверить выравнивание адреса или для сериализации/печати адресов(и то хз). Сложить с указателем нельзя (можно уехать за границу сектора памяти). Те если делать какую то математику в этом типе то обратно нужно вернуть в ptrdiff_t и уже складывать с указателем.

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

в данном кейсе

Как бы данный кейс должен быть проиллюстрировать то, что вот этот тезис – «Точная разрядность нужна редко» – он несколько не такой простой. И даже для счетчика цикла нужно понимать какая у него разрядность.

Не всегда нужно знать точно (16, 32 или 64), но нужно знать, что она достаточна. К сожалению, short, int и даже long не позволяют это знать.

Значит условный Хрюндель верующий в последние, также получит по лбу граблями.

Условному Хрюнделю (включая меня) было бы проще определять тот же самый size_type через int16/int32/int64, а не через short, int или long.

PS. Кстати говоря, еще хороший кейс, на котором легко обосраться, это преобразование int-ового значения в строку с сохранением в char[]. Типа:

char str_value[10];
my_int_to_str(int_value, str_value);

Вот как определить, какая размерность должна быть у str_value когда у нас int плавает туда-сюда, а мы не хотим тратить стек под лишнее?

В тоже время для int16/int32/int64 этот вопрос решается гораздо проще.

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

Правильно ли я понимаю что type* - type* == ptrdiff_t

Строго говоря стандарт определяет операцию разности указателей только если оба принадлежат одному массиву. И понятно почему. Другой вопрос что все настолько избалованы flat memory model и болт на это клали.

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