LINUX.ORG.RU

Накидайте книг для продвинутого Си под онтопик

 ,


10

6

Сто лет назад прочитал K&R и всегда хватало, а если я хочу углУбить?

// друг спрашивает :)

UPD: собрал из темы списочек, особо не редактируя (экстримов и модернов поболее одного, но пусть будет) – думаю, заглянувшим в будущем будет полезно:

  • modern c by jens gustedt
  • Thomas Mailund - Pointers in C Programming (2021)
  • Gustedt - Modern C (2020)
  • Kalin - Modern C Up and Running (2022)
  • King - C Programming. A Modern Approach, 2nd ed. (2008)
  • Хэзфилд «Искусство программировани на C»
  • «Язык C в XXI веке»
  • Экстремальный Си
  • extreme c programming
  • «UNIX. Профессиональное программирование» Уильям Ричард Стивенс, Стивен А. Раго
  • C Interfaces and Implementations: Techniques for Creating Reusable Software
  • Peter van der Linden, Expert C Programming: Deep C Secrets https://progforperf.github.io/Expert_C_Programming.pdf
  • Чан Теренс «Системное программирование на С++ для Unix»
★★★★★

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

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

Если тебя пугают низкоуровневые особенности архитектур то тебе следует срочно переходить на питон или пхп. Хотя в пхп разрядность целых чисел тоже зависит от проца, так что на питон.

А вообще

она зависит от конкретного типа и архитектуры ёвм

Тип «беззнаковое целое 16 бит» от архитектуры не зависит, и 3-2 будет 0xFFFF всегда. У типа «беззнаковое целов 32 бит» ответ будет всегда 0xFFFFFFFF. Замечу, что это же относится и к сложению, когда ты 0xFFFF+1 сделаешь на 16 битах, получится ноль.

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

Тип «беззнаковое целое 16 бит» от архитектуры не зависит, и 3-2 будет 0xFFFF всегда.

почитай разность беззнаковых 3-6 в 16 битах и в 32 битах и сравни результат на эквивалентность.

в знаковых результат один и тот же. и не надо оперировать переполнением как вполне себе нормальной практикой в конвенциальном программировании.

чел хочет получить -1, а не некую фуету под названием - максимальное беззнаковое число.

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

почитай разность беззнаковых 3-6 в 16 битах и в 32 битах и сравни результат на эквивалентность.

Разные типы - разные результаты. То, что тебя это пугает - твои личные проблемы. И повторю, со сложением то же самое, и у знаковых чисел тоже то же самое, вычти -127-2 на 8 битах и на 16 и сравни.

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

Надо, надо. Уже писал, не нравится - учи питон. А Си для того, когда ты оперируешь всем чем можешь и не боишься.

чел хочет получить -1, а не некую фуету под названием - максимальное беззнаковое число.

Гнать надо такого «чела». Видимо он как и ты не понимает что такое арифметика по модулю.

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

И повторю, со сложением то же самое, и у знаковых чисел тоже то же самое, вычти -127-2 на 8 битах и на 16 и сравни.

тут произошло переполнение и результат операции некорректен. полностью лечится взятием более длинного знакового типа.

в беззнаковом случае ви смеете утверждать, что любой результат корректен!!! вне зависимости от разрядности. просто они разные…

а на самом деле в безнаковом случае, НЕКОРРЕКТЕН ЛЮБОЙ РЕЗУЛЬТАТ. и повышением разрядности это не лечится. что я и пытаюсь вам безуспешно донести.

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

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

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

alysnix ★★★
()

Да как же так получается в этих ваших интернетиках: что ни выкальщик, так всегда долборазнообразный? И куда бежать от этого вечного сентября?

Исключение - деды за 70, которые ещё при этом не интернет-старожилы. Потому что последние верны традициям и воспринимают выканьё как удар кулаком в лицо.

anonymous
()

Передай другу, чтобы он внимательней покурил «Введение» оно же «Предисловие» этого вашего К&Р (зависит от редакции). Там есть все вопросы на его ответы.

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

‘‘‘go to’’’ давно только в музее показывают )

Открой исходники webp, там почти в каждой функции юзается goto. И представь себе, с ним код более читаемый. Так что проблема не в самом goto, а в том, кто и как его юзает.

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

Не, наоборот: нужны очень веские причины чтобы совать инт. Размеры обычно или size_t или что-то специальное типа off_t, протокольные чиселки имеют фиксированную длину, а счетчики u64 и выше.

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

прям вот авторы сишечки дураки вовсе. для «малоупотребительного» типа ввели короткое имя… а для «предпочтительного» - длинное.

int - самое короткое имя типа в сишечке. а signed - самое длинное

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

когда хочешь «углубить» - надо уже писать.

пишу, несомненно углубляется, теперь хочется на новом уровне познать теорию, чтоб потом на новом уровне писать

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

сырци сырцам рознь

посмотри The Stanford GraphBase Кнута книга и библиотека пример граммотных сырцов с. https://github.com/ascherer/sgb/blob/master/README.md

просмотри сырцы и многотомия tex тож - полный проект и дока с лирикой

опятже таненбаум с 3 разными книжками по minix

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

qulinxao3
()
Последнее исправление: qulinxao3 (всего исправлений: 2)
Ответ на: комментарий от peregrine

Худлит на английском читать быстрее.

Почему? Опиши, пожалуйста. На русском ты сразу строчку, а то и несколько строчек воспринимаешь ( ну – я ), и еще успеваешь обдумать, повспоминать смешные случаи из жизни, «поспорить с автором» в голове.

Мало практики. Надо больше читать, на определённом этапе переводить себе на русский чтобы понять станет ненужно.

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

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

Кросплатформенность - достаточно веское основание?

Конечно нет. Во первых - это миф: Вы не можете задекларировать «мы совместимы с X» пока на X не оттестируетесь (мы с господином @eao197 на эту тему уже схлёстывались - от тоже сторонник «переносимости заранее»). Причём далеко не всё от Вас зависит - как минимум Вы заложник компилятора и рантайма. Сразу оговорюсь - существуют use-cases когда exact layout важен (SHM, IPC, persistence etc), но их число сильно ограничено, и я сейчас не про эти случаи. Во вторых - даже если бы меня интересовала совместимость с гипотетическими платформами гораздо важнее была бы скорость: вдруг там native ints 40-битные (например), а всё остальное медленно-медленно эмулируется? Ну, Вы поняли идею.

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

Не, наоборот: нужны очень веские причины чтобы совать инт. Размеры обычно или size_t или что-то специальное типа off_t, протокольные чиселки имеют фиксированную длину, а счетчики u64 и выше.

Я не имел в виду domain-specific typedefs. Безусловно - там где задан «целевой alias» использовать нужно именно его. Я об int vs int8_t vs int16_t vs int32_t vs int64_t и их unsigned counterparts. Другими словами - там где размер «гвоздями прибивают» на усмотрение кодера.

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

40-битные (например), а всё остальное медленно-медленно эмулируется?

Да, и кстати - я слышал о DSP где арифметика ни в одном глазу не 2-complimentary: вместо традиционного rollover Вас тупо режут по INT_MIN/MAX. Но я от этого мира очень далёк и мало что знаю.

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

прям вот авторы сишечки дураки вовсе

апелляция к авторитетам. Мне так на позапрошлой работе говорили: «наверное же генерал не тупее тебя, молокососа, не смей отрицать [какую-то там очередную чушь типа плоской земли] которую генерал вещает в ютуб»

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

можно то же самое но по Erlang/scheme? прост спамить топиками неохота чтот.

придется, тут эту просьбу два с половиной луддита сишника увидят

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

А что новичка в C читать?

Да, наверное, первый попавшийся учебник сойдет, но конкретный порекомендовать не могу

K&R актуален?

Всегда актуален. Но есть мнение, что там учат неправильному ( хотя уж сям-то учат ), но подходы/приемы по современным меркам критикуются. Но если у тебя голова на месте – уж точно стоит прочитать, даже любопытно будет из нашего времени взглянуть туда

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

Вы не можете задекларировать «мы совместимы с X» пока на X не оттестируетесь (мы с господином eao197 на эту тему уже схлёстывались - от тоже сторонник «переносимости заранее»).

Простите, уже не помню этого спора, склероз-с…

Но я таки придерживаюсь аналогичного мнения: декларировать «мы совместимы с X» можно только когда на X оттестируетесь.

Другое дело, что если заранее подумать о переносимости, то тестироваться на X буде сильно (по моим впечатлениям очень сильно) проще.

Как я понял, у вас тут спор про выбор между int (без учета его размерности) и условными int32_t/int64_t (с учетом размерности). Вопрос, как по мне, непростой.

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

Есть ситуации, когда нам нужно понимать допустимые рамки для значений. Например, мы делаем вычисления и предполагаем какие максимальные значения могут возникать в процессе этих вычислений. Ну типа есть картинка 10000x10000, мы ее хотим увеличить в 100 раз, поместятся ли итоговые размеры в нужный нам тип? Т.е. как бы простой short уже не подойдет. Да и для int-а хотелось бы понимать, что он 32-битовый по меньшей мере.

Или другая ситуация, но из той же оперы. Нужно читать текстовый файл и вести подсчет строк. Какой целочисленный тип нужно выбрать для этого? При нынешних размерах дисков текстовый файл размером больше 4Gb ну вот вообще не проблема. А если он из одних пустых строк? Подойдет ли простой unsigned int для такой цели?

Т.е. я к тому, что размеры целых нужно выбирать отталкиваясь от задачи. Хотя и есть некоторые простые случаи (вроде кодов ошибок и перечислений), когда о размерностях можно не думать. Но и здесь могут быть случаи, когда код ошибки построен хитрым образом – вроде того, что старшие 4 бита означают класс ошибки, следующие два бита еще что-то, потом сколько-то бит еще что-то и только младшие 16 бит сам код. Тут так же придется смотреть на размерность типа для хранения такого кода.

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

расскажи что на ангельском тебе так же легко читается как на русском

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

По крайней мере, у меня так. Видимо, практика и тут решает.

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

Почему? Опиши, пожалуйста. На русском ты сразу строчку, а то и несколько строчек воспринимаешь ( ну – я ), и еще успеваешь обдумать, повспоминать смешные случаи из жизни, «поспорить с автором» в голове.

Аналогично на английском. В среднем слова короче, особенно литературные. У нас 5,5 букв в литературном языке средняя длина слова, у англичан 5.1. Можно сказать что артикли удлиняют, но более простая пунктуация, и тот факт, что в 95% случаев артикль не важен для быстрого чтения, как и ряд глаголов, самый важный из которых is/are, позволяет парсить текст быстрее.

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

Я прошлый год читал на английском 4 дня в неделю по 3 часа в день и 3 дня на русском (3*60*500=90 000 слов в день, пусть я иногда отвлекаюсь или задумываюсь и начинал чуть медленнее округлим вниз до 80 000 слов, в году 52 недели значит читал я 208 дней в год выходит окло 16 640 000 слов, как по мне вполне достаточно даже чтоб без таланта к языкам научиться читать). Но читаю я быстро, так что это около 500-550 слов в минуту, 600 на мой взгляд слишком быстро для русского языка, начинаю терять контент (правда я на русском измерял с какой скоростью я читаю, на английском не смотрел, но думаю что так же, может быстрее). Такого объёма в течении 2 лет как по мне достаточно чтоб разница ушла. 4 года назад я ещё брал словарь/гугл переводчик и слова туда вбивал незнакомые, начинал с того что в день пару десятков раз переводчиком пользовался, а если у автора богатый язык то и сотню, сейчас хорошо если за неделю 1 раз гляну что-то незнакомое.

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

Т.е. я к тому, что размеры целых нужно выбирать отталкиваясь от задачи.

Не в бровь, а в глаз.

Как я понял, у вас тут спор про выбор между int (без учета его размерности) и условными int32_t/int64_t (с учетом размерности).

А вот Вы в курсе были что на 32ух битах int64_t алиасится в long long, а на 64ёх в long? Хотя казалось-бы - зачем? MS в этом смысле поступили гораздо мудрее сделав long одинаковым везде. Это вызывает существенные проблемы, например если у Вас long забанен во всех IPC процедурах. И в обозримом будущем сему ляпу фикса не предвидится, так как long и long long - это разные типы даже если sizeof and everything else is the same, и смена int64_t алиасинга означает слом ABI.

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

А вот Вы в курсе были что на 32ух битах int64_t алиасится в long long, а на 64ёх в long?

Нет.

Хотя казалось-бы - зачем?

Действительно, а зачем мне это знать?

Это вызывает существенные проблемы, например если у Вас long забанен во всех IPC процедурах.

Во-первых, вроде бы вы сами вывели область IPC за скобки разговора:

Сразу оговорюсь - существуют use-cases когда exact layout важен (SHM, IPC, persistence etc), но их число сильно ограничено, и я сейчас не про эти случаи.

Во-вторых, если речь про IPC, persistence и пр, то использование там short/int/long вместо int16/int32/int64 – это прямой путь к проблемам. По крайней мере по моему опыту.

С shared-memory ситуация попроще, если речь идет о ситуациях, когда приложение на C++ форкается для реализации многопроцессной работы и форки одного приложения общаются между собой через shared-memory.

И в обозримом будущем сему ляпу фикса не предвидится, так как long и long long - это разные типы даже если sizeof and everything else is the same, и смена int64_t алиасинга означает слом ABI.

Мне, наверное, повезло, но пока еще не приходилось заморачиваться на сохранение ABI для разработанных мной (или с моим участием) библиотек.

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

Хотя казалось-бы - зачем?

Действительно, а зачем мне это знать?

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

Это вызывает существенные проблемы, например если у Вас long забанен во всех IPC процедурах.

Во-первых, вроде бы вы сами вывели область IPC за скобки разговора

Посыл следующий: даже там где применение fixed-size алиасов полностью оправдано - не всё так гладко как хотелось бы.

С shared-memory ситуация попроще, если речь идет о ситуациях, когда приложение на C++ форкается для реализации многопроцессной работы и форки одного приложения общаются между собой через shared-memory.

Довольно интересно как Вы это видите. Я не до конца понимаю почему это обязаны быть «форки одного приложения», а уж тем более «форки одной версии одного приложения» - на моей практике такое происходит крайне редко, причём end points зачастую разной битности. Да да - я уже неоднократно говорил что 32 бита более чем живы.

Мне, наверное, повезло, но пока еще не приходилось заморачиваться на сохранение ABI для разработанных мной (или с моим участием) библиотек.

Дело не в Ваших библиотеках. Речь о system-wide ABI ломать который крайне не рекомендуется.

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

Заранее извиняюсь.

Не за что.

Имелось в виду что алиасить в long long в обоих случаях было бы куда логичнее.

ХЗ. Мне в 1990-х приходилось самому выяснять какой тип на каком компиляторе и на какой платформе имеет нужную размерность. Но в 2000-х перешел на использование библиотеки ACE, где это все уже было сделано за меня, а дальше уже и <cstdint> в компиляторах появился. Так что надобности следить за тем, во что раскрывается std::int64_t или std::int_fast64_t уже не вижу.

даже там где применение fixed-size алиасов полностью оправдано - не всё так гладко как хотелось бы.

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

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

Тут все просто. Если у вас всего один исполняемый файл форкается, и у него внутри есть структура типа:

struct data_header {
  unsigned int field_a;
  long long field_b;
  bool field_c;
  double field_d;
};

то вы можете вообще ни о чем ни париться размещая ее экземпляры в shared-memory. Т.к. все экземпляры работающего кода собраны одним и тем же компилятором с одними и теми же параметрами.

А вот если это разные исполняемые файлы (грубо говоря, вы делаете fork+exec, где exec запускает что-то другое), то тут уже нужно заботится и о том, какие размеры, какой режим выравнивания.

Речь о system-wide ABI ломать который крайне не рекомендуется.

Это не в моей власти, так что я об этом не парюсь :)

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

std::int_fast64_t

Хорошая была идея, но «не взлетело»: я ни разу в прод коде этого не видел.

Тут все просто. Если у вас всего один исполняемый файл форкается

Идея предельно понятна. Просто немножко оторвана от реальности. Больше скажу - приходится очень сильно заботиться что и в каком порядке рестартует.

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

Хорошая была идея, но «не взлетело»: я ни разу в прод коде этого не видел.

У нас, пожалуй, найдется. Но какой это продакшен, так, образцовое нинужно (c)

Вообще, типы вроде _fast64_t/_least64_t (и их 32-битовые аналоги) регулярно доводится использовать, т.к., в отличии от просто int64, они обязательны, а не опциональны.

Просто немножко оторвана от реальности.

Ну хз. Я про свой опыт говорил. У меня бывало именно так.

Больше скажу - приходится очень сильно заботиться что и в каком порядке рестартует.

А зачем об этом заботится? В случае обновления бинарников?

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

У нас, пожалуй, найдется. Но какой это продакшен, так, образцовое нинужно (c)

Мне кажется - Вы склонны сильно «преуменьшать свои заслуги перед отечеством» ;) Серьёзно.

Вообще, типы вроде _fast64_t/_least64_t (и их 32-битовые аналоги) регулярно доводится использовать

Я, мягко говоря, удивлён.

А зачем об этом заботится? В случае обновления бинарников?

Именно. Кроме шуток - одно из основных требований к последнему серьёзному обновлению было «делайте что хотите, но предполагать что end points будут обновлены in-sync вы не можете».

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