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)

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

Всё сложно. А какого результата Вы хотите добиться?

Все ж просто с сями :) а хочу почитать книжки, улучшить знания.

Знания из книжек последовательные, полные и настоящие – хочу их

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

Двоичная арифметика давно уже '''deprecated '''

Очень от предметной области зависит.

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

и в ядре этого вашего линупса

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

Знания из книжек последовательные, полные и настоящие – хочу их

Не особо понятно, что это заявление означает в контексте Си.

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

Если уже читал K&R то учебник тоже можно попробовать, но пользы уже будет меньше. Главное усвоить:

1) неявные int-ы в типах функций и переменных делать не надо

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

3) сувать int без разбору для всех целых типов тоже не стоит

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

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

Щас тебе расскажут, что читать такое надо только на английском.

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

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

Сишка медленно развивается (90, 99, 11, 18 в него вообще ничего нового не завезли, пофиксили косяки 11 стандарта только), так что можно и на русском читать. Так что некст стандарта где что-то добавят/поменяют ждать к 28-30 году. Это не python с C# у которых новый стандарт выкатывают раз в год. Да и библитеки/фреймворки там не как грибы после дождя появляются, что характерно для фронтэнда в вебе, несмотря на то что css, html и js не шибко быстро меняются.

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

сувать int без разбору для всех целых типов тоже не стоит

Как мне это видится - нужны довольно веские основания использовать что-либо отличное от plain int. Мне кажется - утверждение как минимум спорно.

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

Кучу кода чинил где из-за чьего-то тупого «суну int по дефолту» были баги. Как минимум, стоит подумать нужен ли тебе знак у этого числа. Во вторую очередь - хватит ли битности во всех режимах компиляции (включая 64-битный, а то некоторые например в 32-only эпоху ставили int для приёма возврата из функции long и оно работало).

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

И таки мне видится что это всё именно наследие со времён K&R.

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

Кучу кода чинил где из-за чьего-то тупого «суну int по дефолту» были баги.

Я уверен что чинил не меньше связанных с чьей-то идеей «8/16 бит здесь хватит». Повторюсь - нужны довольно веские причины откланяться от дефолта, имхо.

Как минимум, стоит подумать нужен ли тебе знак у этого числа.

Где гарантии что никто по дороге не засунет int в unsigned? А потом начинаются проблемы с implicit conversions, -1 suddenly becoming a very large value, etc. Проще оставаться в одном домене, в данном случае - signed integers.

последствие этого тупизма прямо в libc - тип возврата snprintf

Вы о том что оно int а не ssize_t? Как часто Ваши строки не умещаются в 2GB?

И таки мне видится что это всё именно наследие со времён K&R.

Это прямое следствие ABI, и предположения «int» - это самый быстрый integral type on a target platform, register size basically - в частности в случае x86 ints возвращаются в eax, что dirt cheap.

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

Я уверен что чинил не меньше связанных с чьей-то идеей «8/16 бит здесь хватит». Повторюсь - нужны довольно веские причины откланяться от дефолта, имхо.

Когда ставят int32 вместо int8 это в целом терпимо, я не про это писал.

Где гарантии что никто по дороге не засунет int в unsigned? А потом начинаются проблемы с implicit conversions, -1 suddenly becoming a very large value, etc. Проще оставаться в одном домене, в данном случае - signed integers.

Вот если в разработке есть чёткое правило «следи за знаковостью», а лучше ещё чтоб компилятор варнинг выдавал на такие конвертации (не знаю есть ли, лень искать, поставил бы себе), то таких случаев не будет. А когда принято наобум ставить везде int - как раз получается бардак.

Вы о том что оно int а не ssize_t? Как часто Ваши строки не умещаются в 2GB?

Дело не в том «как часто» а в том, что это нелепое условие «не вылезайте за 2гб» придётся тащить по цепочке везде, где используется так или иначе printf - а условие это не имеет под собой никаких объективных причин, засоряет «контракты» всех написанных на этой базе функций (и мысли программистов, ими пользующихся, потому что не держать такое в голове нельзя), ну и в конце концов изредка и правда чему-то мешает. Выход тут только один - выкидываем printf и пишем свою реализацию без этого ограничения.

Это прямое следствие ABI, и предположения «int» - это самый быстрый integral type on a target platform

Вот только на 64 битах нативный тип уже long, хотя по скорости с int он наверно примерно одинаковый.

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

даже английский не осилил

Омайгадбл

Давай, расскажи что на ангельском тебе так же легко читается как на русском и что тебе без разницы на каком читать

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

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

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

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

Он есть. Я даже «по молодости» пытался это фиксить в меру возможностей: сизифов труд должен заметить - по факту проблем я принёс больше чем порешал. Сейчас в наших прод сборках конкретно этот warning отсушен.

что это нелепое условие «не вылезайте за 2гб» придётся тащить по цепочке везде

Вы упускаете из виду довольно очевидный факт что если Ваши строки не умещаются в 2GB - с огромной вероятностью Вы что-то делаете не так.

Вот только на 64 битах нативный тип уже long

С long у меня отдельная история, в частности с фактом что он разный на 32 и 64 битах. У нас он «забанен» к использованию (любой код его использующий review не пройдёт).

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

Вы упускаете из виду довольно очевидный факт что если Ваши строки не умещаются в 2GB - с огромной вероятностью Вы что-то делаете не так.

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

С long у меня отдельная история, в частности с фактом что он разный на 32 и 64 битах

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

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

а не про особенности его прикладного применения.

Я ждал пока Вы это скажете. Вот оно. Вот она разница между «сферическим конём в вакууме», и практикой. Вам «шашечки или ехать»?

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

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

Вообще даже ssize_t вместо size_t - не очень хорошо, я в результате часто пишу к ним обёртки для устранения этого ограничения (запись несколькими кусками если длина не влезает в ssize_t). Вот например функция strlen() вполне работоспособна даже если строка будет длиной в SIZE_MAX (хотя непонятно где тогда будет располагаться собственно код strlen(), но это дела не касается).

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

я в результате часто пишу к ним обёртки для устранения этого ограничения (запись несколькими кусками если длина не влезает в ssize_t).

Я реально не до конца понимаю зачем Вы это делаете. Как по мне - практический смысл стремится к нулю…

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

Я сторонник идеи «garbage in - garbage out».

garbage in - exploit out

Я реально не до конца понимаю зачем Вы это делаете. Как по мне - практический смысл стремится к нулю…

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

Ну представь, сегодня он пишет блоки по 10мб, через 10 лет понадобится писать по 3гб на 32 битах. Откуда кто-то должен будет вспомнить, что функция от такого размера блока молча устраивает чушь?

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

Чисто прикладной код может иметь какие угодно прикладные ограничения, а системные низкоуровневые функции - не должны.

Вообще даже ssize_t вместо size_t - не очень хорошо

Внезапно size_t - тоже ограничение.

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

Вообще-то нет. Если ты про то, что бывает sizeof(void*)>sizeof(size_t), то Си нативно не поддерживает объекты, расположенные через границу сегментов, а максимальный размер одного сегмента как раз будет соответствовать size_t. Конечно, можно закодить сверхдлинные кросссегментные массивы, но то другая история и size_t к ней уже ни при чём.

Единственное, чего не влезет в size_t - это сам размер сегмента, да, но тут разница всего в 1 байт и она так сказать стандартизирована.

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

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

операция разность для беззнаковых уже есть почти UB. и для беззнаковых она должна быть запрещена.

карочи, если поц написал unsigned - с поца надо немедленно спросить - зачем он это сделал. неужели знакового ему не хватило?

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

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

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

Ну представь, сегодня он пишет блоки по 10мб, через 10 лет понадобится писать по 3гб на 32 битах.

Знаете в чём разница в наших подходах? Я сегодня платить за то что мне завтра может быть понадобится - не собираюсь. Вот и всё…

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

сам не позорься. ты из 2 не вычтешь 3 если сильно залюбил беззнаковые. со всеми вытекающими.

а числовой тип который не имеет вполне корректной операции минус, уже не поддерживает арифметики целиком.

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

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

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

а в знаковых разность 2-3 будет всегда минус 1. на любой архитектуре.

alysnix ★★★
()