[О блоге] [наверх] [пред] [2022-07-04 14:41:07+03:00] [5f1645eb510d76ffb07c07fa09bffdea01959c03]

Тип переменной индекса массива в Си

https://stackoverflow.com/questions/3174850/what-is-the-correct-type-for-array-indexes-in-c
https://sergvasiliev.medium.com/about-size-t-and-ptrdiff-t-a1654234d842
Вот размеры и длины я привык (и считаю корректным) указывать в size_t.
Но если хочется итерироваться по массиву, указывать элемент в нём, то
какой тип применять для переменной содержащей индекс? size_t плох тем,
что он беззнаковый, так что при логической ошибке или переполнении его
значение может стать огромным из-за переполнения и оно уйдёт в
бесконечный цикл например. Подобное отлаживать не очень приятно. А я уже
не раз напарывался на подобную ошибку.

Хочется использовать число со знаком. int может быть слишком маленьким.
ssize_t определён только в POSIX и гарантирует только [-1, SSIZE_MAX].
Куча людей указывается на ptrdiff_t. Но и он может, очевидно, быть
меньше size_t.

Посмотрел код всяких других проектов серьёзных, типа Redis. Они все
size_t используют. И пока я тоже остаюсь на нём, не забывая про косяки
неприятные во время разработки.

    [оставить комментарий]
    комментарий 0:
    From: David Rabkin
    Date: 2022-07-16 21:15:05Z
    
    Я использую size_t по странной причине. Много лет у меня любимый макрос:
    #define ARRAYSIZE(arr)                              \
    (                                                   \
        (sizeof(arr) / sizeof(0[arr])) /                \
            ((size_t)(!(sizeof(arr) % sizeof(0[arr])))) \
    )
    
    Тут он улученный до полной непонятности, но идея ясна. Поэтому
    большинство моих циклов выглядят так:
    int arr[10];
    for (size_t i = 0; i < ARRAYSIZE(arr); i++);
    
    Результат макроса имеет тип size_t, но и чтобы не множить сущностей…
    Однако, твои ссылки меня убедили, что правильный вариант все таки
    ptrdiff_t. А макрос можно дополнить привидением типа. Хотя, хрен его
    знает…
    
    Я вспоминаю одного моего начальника, который сказал, что хватит
    выпендриваться, что я в проекте не один, и приказал писать циклы так,
    типа деды, керниганы и ричи, так делали:
    int arr[10];
    for (int i = 0; i < 10; i++);
    
    Я в то время я обожал писать так, это влияние STL из С++:
    #define ARRAYEND(arr) ((arr) + ARRAYSIZE(arr))
    int arr[10];
    for (int *p = arr; p != ARRAYEND(arr); ++p);
    
    Тогда я был возмущен, как мне казалось, тупостью коллег и начальника.
    С годами я все больше понимаю, что начальник был прав.
    
    Через тебя нашел Столярова. Читаю полдня, оторваться не могу. Начал отсюда:
     http://stolyarov.info/faq.html
    
    Ты с ним знаком? Мне нравится его интонация. Крутой, видимо, педагог.
    Чувак старше меня на пару лет, от этого любовь к С++. У нашего
    поколения (я 1976-ого) С++ и ООП — болезнь. Мы, наверное, первое
    поколение, когда программирование пошло в массы. И оно начиналось с
    Design Patterns, UML, OOP и С++. Линус и Пайк — из другого времени.
    
    Скачал все столяровские книги в пидиеф. Он их запрещает
    конвертировать, а у меня читалка с маленьким экранам. Выбираю читалку
    с большим экраном, проблемы :-)
    
    комментарий 1:
    From: Sergey Matveev
    Date: 2022-07-17 09:02:11Z
    
    *** David Rabkin [2022-07-17 00:13]:
    >Однако, твои ссылки меня убедили, что правильный вариант все таки
    >ptrdiff_t. А макрос можно дополнить привидением типа. Хотя, хрен его
    >знает…
    
    Я в итоге пока остаюсь на size_t, ибо уж больно геморройно везде всё
    приводить к эстетически корректному ptrdiff_t/size_t и подобному.
    "Просто" не забывая что size_t без знака и поэтому учитывать переполнение.
    
    >типа деды, керниганы и ричи, так делали:
    >С годами я все больше понимаю, что начальник был прав.
    
    Я всё же тут не соглашусь с твоим начальником :-). Во-первых, даже все
    эти Ричи и Томпсоны очень многое со временем поняли и в Go языке убрали
    100500 фишек которые они же в своих книгах и коде постоянно использовали.
    У них именно выпендрёжа очень много по чуть более короткому, но опасному
    и не совсем очевидному коду. В Go же они явно решили не позволять
    выпендриваться. Как бы... все могут совершать ошибки и не все могут быть
    аккуратными. Код дедов далёк от идеала -- и чем больше я сейчас пишу на
    Си, тем больше это понимаю, много там ходят по краю.
    
    В Go результат len()-а возвращает int, обычный int, размер которого
    зависит от используемой архитектуры. И полно задач и мест где его (2^31)
    будет недостаточно на 32-бит платформах. Но!!! В Go я к этому спокойно
    отношусь, так как язык много где откровенно плюёт на поддержку 32-бит
    систем, имеет нюансы с ними (типа ручного выравнивания структур если
    хочется использовать sync/atomic). И для меня факт использования Go
    означает почти 100% уверенность что эта программа запускаться будет на
    64-бит системах. Как например факт использования ZFS говорит тоже о
    64-бит системе, хотя его и на 32-бит запускают (на свой страх и риск).
    
    А вот Си код, до сих пор, имеет огромные шансы запускаться на 32-бит
    решениях. Предполагать что программу не будут использовать для,
    например, 3-х миллиардов записей в СУБД -- я считаю опрометчивым и опыт
    человечества, и кстати многочисленных програм "дедов", показал что
    регулярно куча програм имеет ограничения из-за "узких" целочисленных
    типов. Это и форматов касается, и протоколов и тьмы софта, где обычный
    int уже не справится с десятками гигабайт обрабатываемых данных.
    
    Даже банально вот передача IP пакета: казалось бы, должно хватить и
    16-бит, ведь в заголовке IPv6 больше просто и не уместится. Но я помню
    про его расширенные заголовки, где можно передавать слонограммы вплоть
    до 4-х гигабайт. Будет ли это использоваться на практике? Я не хочу об
    этом думать, но уже сейчас вижу что есть потенциальная техническая
    возможность. Поэтому в программе (внутри неё) я частенько буду
    использовать всё равно size_t, ибо даже 32-х битного int-а не хватит.
    
    Деды старались выжимать всё из железа и экономить на всём. Лично я в
    данных вещах считаю что экономия чересчур может быть излишня. Ага,
    поэтому у нас из-за такого подхода и софт медленный стал :-)
    Вот у меня на одном разделе (8e24a68248865cfcd58538871f8b96e6327376d8)
    есть 17.5M файлов, где 32-х битного int-а должно быть достаточно для их
    записи. Но я стараюсь рефлекторно задаваться вопросом "а что будет если
    оно вырастет на порядок?". И это уже начинает занимать ощутимую долю
    int-а, хотя вроде бы и далёкую. Поэтому для порядкового номера файла я
    всё равно стал бы использовать что-то 64-х битное. Не даром в ZFS
    применяют и 128-бит числа уже.
    
    >Через тебя нашел Столярова.
    >Ты с ним знаком?
    
    Не знаком лично, но кроме имени стал больше о нём что-то понимать после
    его длинного интервью (d026b3c3e20a717c7fd8aad8f5377c4fc4b90d0b). С
    одной стороны, в первой части интервью, я как-будто смотрю на себя
    самого в "старости", ибо тьма мест где мы полностью в резонансе
    совпадает друг с другом. С другой стороны: потом начинается какая-то
    лютая дичь, полностью не совпадающая с моими представлениями и отношением.
    Он меня впечатляет тем, что в одних местах говорит очень правильно (с
    моей точки зрения), чего я полностью поддерживаю, а в других несёт
    полнейшую фигню, типа отношения его к UTF-8
    (3b209b82b1de228059953f07f69bcb49ee2edea6). Или вот он (в FAQ это было)
    считает что C99 не должен использоваться, ибо там VLA. Да, даже я, без
    сторонней помощи, понял сразу же что VLA это точно лютое зло, не имеющее
    право на существование. Но выбрасывать абсолютно всё остальное что есть
    в C99 и при этом писать на C89? Ему намекают что можно добавить warning
    для компилятора чтобы он ругался на факты использования VLA. Да, это
    некрасиво, это безусловно костыль. Но это меньшее зло, чем C89, где, как
    минимум, объявления переменных должны быть в начале функции -- идёт это
    старьё в жопу. Даже мелочи типа inttype.h, stdbool.h и designated
    initializers (https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Designated-Inits.html)
    для меня являются killer-feature.
    
    >Чувак старше меня на пару лет, от этого любовь к С++. У нашего
    >поколения (я 1976-ого) С++ и ООП — болезнь. Мы, наверное, первое
    >поколение, когда программирование пошло в массы. И оно начиналось с
    >Design Patterns, UML, OOP и С++. Линус и Пайк — из другого времени.
    
    Согласен что вы другого поколения. При вас, так сказать, ещё не было
    огромного опыта человечества и вообще понимания людей как они себя ведут
    и как пишут код. Go вот создан для современного поколения, типа меня,
    где учтены особенности людей, которые не могут быть настолько
    аккуратными как "деды" в коде. Я на личном опыте убедился что Си это не
    про то, как не выстрелить себе в ногу, а про то, что ты как на минном
    поле -- обязательно подорвёшься и вопрос "когда и как сильно". А Ритчи,
    Томпсоны и Пайки это вообще по сути сплошной computer science в головах.
    
    >Скачал все столяровские книги в пидиеф. Он их запрещает
    >конвертировать, а у меня читалка с маленьким экранам.
    
    Вот кстати тоже пример "странности" Столярова. С одной стороны он даёт
    их читать бесплатно, без регистрации и SMS. С другой -- всё равно
    вставлять палки в колёса, типа чтобы студенты не слепо копировали: не
    согласен с этим. Это не ему решать за людей как и что им следует делать.
    Я понимаю что студенты, действительно, будут так поступать, но повышение
    порога входа не является решением и оно больше проблем приносит. Но он
    автор, владелец -- так что это его полное право и вообще огромное
    спасибо что он хотя бы в таком виде их выдаёт. Или с начала спецоперации
    так он вообще на сайте одну статичную страницу повесил о том, что мол
    сейчас всё непонятно и вообще не время для его книжек типа. Ну какая тут
    нахрен взаимосвязь? Тебе надо свою уродскую политическую позицию донести
    или же всё же программирование, образование важнее? Но тема политики
    конечно вечная и больная.
    
    В итоге он у меня больше негатив вызывает, ибо зачастую я с ним люто не
    согласен (и в технических вещах тоже), а у него слишком безапелляционная
    риторика. Подписан вот на рассылку TUHS, где и Пайки и всякие деды
    постоянно общаются и на связи. У всех нормальный тон, ни у кого нет
    звёздной болезни, никто не поливает так яростно дерьмом как это делает
    Столяров. Возможно разность культур: у нас можно и нахер послать и это
    нормально, но Столяров перебарщивает со своей звёздной болезнью.
    
    Или я вот не нашёл НИКАКОГО способа как с ним связаться, ибо нашёл
    несколько опечаток/ошибок где-то на сайтах или материалах. Нашёл только
    в каком-то не самом свежем его софте адрес на МГУ домен -- но там никто
    не ответил. Видел что у него на сайте есть обратная связь с CAPTCHA. Но
    я честно и упорно раз 20, не совру, пытался её решить -- ни разу не
    вышло. Здорово что она без JS, чисто HTML, но только я её не смог
    решить. Может у меня проблемы со зрением или распознаванием образов,
    проблемы с головой? Может. Но это не отменяет того, что я просто
    физически не знаю как с ним связаться и искренне указать на опечатки. В
    своём интервью он оставлял email для конкурса что ли какого-то (уже не
    помню), но писать туда по совершенно сторонним вопросам не считаю
    приемлемым с этической стороны. Может быть ещё какой-то email где-то
    находил, но тоже никакого отклика. Безусловно, он никому ничего не
    должен, и он вправе не хотеть светиться контактами, но единственное что
    я смог ему отправить, так это только пожертвование (поэтому моё имя
    засветилось в его книге), а вот по другому вопросу не вышло связаться.