LINUX.ORG.RU

Новое слово в программировании на C: штатное определение количества элементов в массиве

 ,


1

2

Привет, ЛОР!

Тихо и незаметно во всеми нами горячо любимый язык программирования Си решили наконец добавить новый оператор, возвращающий количество элементов в массиве. То есть, аналог вот такого:

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

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

Ссылка на опрос: https://www.allcounted.com/s?did=qld5u66hixbtj&lang=en_US

Статья от автора предложения: https://thephd.dev/the-big-array-size-survey-for-c

Что скажут эксперты в программировании на C по поводу этого нововведения? Нужно ли оно? Станет ли язык Си ещё лучше?

★★★★★

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

Конечно нужен. Потому что (sizeof(x) / sizeof(x[0])) прекрасно работает на указателях, возвращая тебе полную срань.

И что? Когда подразумевается использования указателя, то никакого (sizeof x / sizeof *x) быть не может. Длину массива передают отдельной переменной.

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

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

Да, да, да. -fno-strict-aliassing, -fno-vla (для C99 и выше) и т.п., продолжать? С этими флагами собирается каждый второй проект на «современном» С, а вторая половина проектов собирается с -ansi. Все забили на эту макулатуру. Во многих проектах, которые собираются даже ужасным C99 (естественно с опциями, выключяющими бред сумасшедших стандартизаторов), используется форматирование объявление переменных, затем код, в стиле ANSI C; запрещаются комментарии с стиле C++ и т.п. Вот на таком Си пишут, а на С23 или что там они придумали — не пишут.

Вот именно. А макрос (sizeof(x) / sizeof(x[0])) скомпилируется и будет работать в том числе на них, но выдаст полную херню как результат. Так быть не должно.

Вот не поверишь, это ни разу не вызвало проблем в реальных программах. Функции получают указатель на буфер и его размер. Функции должно быть пофигу, на стеке лежит объект или в куче. Ну а если ты создаешь буфер, то его размер ты выносишь в константу, либо через #define, либо через enum, который просто указываешь при создании и при вызове функции.

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

Вот на таком Си пишут, а на С23 или что там они придумали — не пишут.

Ага. Потому что C23 только вышел. Сишники тормозные, но лет через пять фичи оттуда будут использоваться. Так же как фичи из C++17 используется много где сегодня.

Вот именно. А макрос (sizeof(x) / sizeof(x[0])) скомпилируется и будет работать в том числе на них, но выдаст полную херню как результат. Так быть не должно.

Вот не поверишь, это ни разу не вызвало проблем в реальных программах.

Тебе не поверю, ты же не знаешь сишки. В линуксовом ведре примерно 47 тысяч вызовов макроса ARRAY_SIZE(). Быстрый греп по git log показывает, что баги там вокруг этого макроса таки были.

Ну а если ты создаешь буфер, то его размер ты выносишь в константу, либо через #define, либо через enum, который просто указываешь при создании и при вызове функции.

Мне нравится, что в том же линуксовом ведре куча коммитов с описанием типа «Use sizeof() and ARRAY_SIZE() instead of hard-coding buffer sizes and indices.», что лишний раз подтверждает, что ты п7*?*бол.

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

И что? Когда подразумевается использования указателя, то никакого (sizeof x / sizeof *x) быть не может. Длину массива передают отдельной переменной.

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

ВСЕ

СЕРЬЕЗНЫЕ

ПРОЕКТЫ

СТАРАЮТСЯ

МИНИМИЗИРОВАТЬ

ОШИБКИ

Вбейте это себе в ваши тупые головы. Если вы этого не делаете, значит ваши проекты – поделки для школотронов.

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

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

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

ВСЕ СЕРЬЕЗНЫЕ ПРОЕКТЫ СТАРАЮТСЯ МИНИМИЗИРОВАТЬ ОШИБКИ

Поэтому пишут код на Rust-е, а не на си

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

чо? Кто тебе такую херню сказал?

Какую херню? Ты когда malloc-ом память выделяешь, где тебе какой оператор поможет? Ты либо будешь размер в переменную записывать, либо в случае «массива строк» через while(*str) { ... str += strlen(str) +1; } через нулевой символ проводить итерацию. Такое я тоже видел.

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

P.S. Кстати, если передать в функцию массив, то ругнётся: https://stackoverflow.com/questions/25680014/find-the-size-of-integer-array-received-as-an-argument-to-a-function-in-c

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

Какую херню?

Что указатели – это про динамическую память. Указатели – это не только про динамическую память.

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

P.S. Кстати, если передать в функцию массив, то ругнётся

Это самодеятельность GCC, а не стандарт языка.

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

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

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

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

Ох… я понимаю что в школьных поделках это не проблема. Во взрослых программах люди развивают кодовую базу.

Например, вот так:

- char array[32];
+ char *array;

…

nelm = ARRAY_SIZE(array);

На это нарывались везде, включая ядро. Поэтому ядро проверяет, что ты не пытаешься использовать ARRAY_SIZE на указателе. Наконец-то в gcc догадались и начали делать то же самое. Но это вообще не отменяет того, что пора бы уже заиметь нормальную встроенную конструкцию для определения длины.

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

На это нарывались везде, включая ядро.

Ты несешь лютую дичь. Во-первых, я не могу представить себе такую ситуацию когда нужно ВНЕЗАПНО поменять поле фиксированного размера на указатель на массив в памяти. Если по дизайну кода массив фиксированный (значение поля в протоколе, например), то он фиксированный всегда. Попахивает говнокодерством, но я думаю ты просто высосал это из пальца. Второе, это всё бессмысленно, если у тебя массив фиксированного размера то придётся писать sizeof(array) в функциях, потому что там указатель и длина void func(char *array, size_t len), а если по какой-то не понятной причине меняешь на динамический массив, то всё равно нужно будет редактировать весь код. Как тут вообще можно ошибиться? В общем, научно доказано, что школоло тут ты.

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

Тебе не поверю, ты же не знаешь сишки.

Ну посмотри API OpenSSL, например.

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

Уверен? Sqlite3 собирается с -ansi, SDL2 собирается с -ansi, MySQL C API собирается с -std=gnu89, все проекты OpenBSD, в частности очень популярных OpenSSH, собираются с -ansi. И даже ляликс хоть и использует «современный» С, требует оформлять код в стиле ANSI C, использует упомянутые флаги.

Покажи хоть один стоящий проект на C11, чтобы еще в нем не «откручивали» все до уровня ANSI C через -fno...

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

Я не использую VLA. С99 это самый портабельный стандарт Си, stdint.h и long long. Меня бесят любители С89 что городят адские горы из директив препроцессора лишь чтобы сделать свой аналог intptr_t. Часто они настолько в прошлом, что не знают о том что давным давно уже появилось много способов определить разрядность архитектуры по предустановленным макросам (например __LP64__) и нахерачивают белые списки проверок архитектур поимённо, где все архитектуры не в списке по умолчанию 32-бит. Когда новые архитектуры уже рождаются 64-битными. Вот это реально больные люди.

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

Ну посмотри API OpenSSL, например.

Он мне тоже покажет, что ты не знаешь сишки?

Покажи хоть один стоящий проект на C11,

Да пожалуйста.

https://www.phoronix.com/news/Linux-Kernel-C89-To-C11

Прикол в том, что между C99 и C11 отличий не то чтобы много. Туда добавили фичи, которые и там были в компиляторах, типа анонимных struct и union. Единственная действительно оригинальная новая фича – _Generic, и её вот никто нигде не использует, потому что она бесполезна чуть более чем полностью. А в C17 новых фич вообще нет, это целиком версия с исправлениями говна. Так что не понимаю, почему у тебя так жопу рвёт от увеличения циферки.

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

Во-первых, я не могу представить себе такую ситуацию когда нужно ВНЕЗАПНО поменять поле фиксированного размера на указатель на массив в памяти.

Это твой недостаток.

В общем, научно доказано, что школоло тут ты.

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

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

И даже ляликс хоть и использует «современный» С, требует оформлять код в стиле ANSI C, использует упомянутые флаги.

Это чисто coding style issue:

It’s a coding style issue. We put our variable declarations where people can find them, not in random places in the code. Putting variables in the middle of code only improves readability when you have messy code. Now, one feature that may be worth it is the loop counter thing: for (int i = 10; i; i–) kind of syntax actually makes sense and is a real feature (it makes ‘i’ local to the loop, and can actually help people avoid bugs– you can’t use ‘i’ by mistake after the loop)."

А так они вполне ползут себе на c11. Никаким ANSI там не пахнет, лялекс отчаянно прибит к GCC, причем не меньше 5 версии.

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

Этот define говно, не работает для multidimensional arrays

А можно пример где именно не работает?

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

int main(){
  double arr[10][20];
  printf("%i\n", ARRAY_SIZE(arr)); //все правильно, 10
  printf("%i\n", ARRAY_SIZE(arr[1])); //все правильно, 20
}
COKPOWEHEU
()

Не эксперт по Си, но имею сказать две вещи:

  1. Кажется что т.к. устоялся макрос то отдельное ключевое слово не нужно. Да я вскольз пролистал коммнты - типа этот макрос сработает и на указатели и выдаст непонятно что - но ведь это Си и тут надо быть внимательным а не через дополнительные абстракции обезопасивать язык.

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

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

но ведь это Си и тут надо быть внимательным а не через дополнительные абстракции обезопасивать язык.

Лол ещё один

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

Какое-то бессмысленное нововведение.

Лучше бы сделали возожность использовать строковые константы в switch(x){ case "sometext": ... break; ... }. Или добавили бы векторы и матрицы в базовые типы данных и соответствующую арифметику (включая всякие транспонирования и декомпозиции) искаропки. А то complex со всеми пирогами есть, а матриц нету. Ну в общем то, что макросами не реализовать.

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

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

Есть ли вариант «не нужно»? Если нет, то подход всё равно плохой. Тебе навязывают ненужную фичу, спрашивают лишь название.

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

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

Это проблема, а не фича языка. Зацени zig. Там тот же уровень абстракций, но при этом нет 80% капканов, которые достались нам в наследство от дедов.

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

Немного практикую. Честно говоря не привык кому-то в интернете что-то доказывать, но если сильно интересно - https://pastebin.com/wHxTrbPz вроде ничего конфиденциального нет, маленькая реализация usb-стека, написал всё сам, тут уж придётся поверить мне на слово. Ничего там интересного, конечно, нет, но интересное показывать я не могу, а с опен сорсом у меня не особо складывается.

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

Лучше бы сделали возожность использовать строковые константы в switch(x){ case «sometext»: … break; … }

Пиши на Rust уже лол

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

Про ненужность однострочных комментариев удобно рассуждать когда ты вообще не пишешь комментариев.

Между тем пара однострочных комментариев:

#endif // NRF52833_XXAA
// NOLINTNEXTLINE(misc-misplaced-const)

Радует K&R стиль. Много == 0 которые можно сократить на !.

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

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

Много == 0 которые можно сократить на !.

Нельзя. Я не на жаваскрипте пишу (хотя я и на жаваскрипте так не писал бы). ! это логический оператор и должен применяться к логическим значениям. Применять его к int это как раз из разряда вредных фич.

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

Нельзя. Я не на жаваскрипте пишу. ! это логический оператор и должен применяться к логическим значениям. Применять его к int это как раз из разряда вредных фич.

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

Применять его к int это как раз из разряда вредных фич.

А к указателям применять так вообще смертный грех?

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

Пиши на Rust уже лол

Ну как появится задача для которой именно раст будет оптимален и оправдан - несомненно напишу. Пока что таких задач ни разу не попадалось. А писать на расте исключительно ради писания на расте - клинический идиотизм.

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

А тут дело не в консервативности, а в здравом смысле. Я пишу код, который я потом буду читать. Поэтому любое неявное поведение для меня это красный флаг. Когда я читаю код, чем меньше мне приходится задумываться, пытаясь его расшифровывать, тем лучше. Использование ! вместо == 0 это как раз тот самый пример неявного поведения, которое придётся расшифровывать в уме, читая код, создавая совершенно ненужную когнитивную нагрузку.

Применять его к int это как раз из разряда вредных фич.

А к указателям применять так вообще смертный грех?

Да ровно те же самые рассуждения.

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

А к указателям применять так вообще смертный грех?

С указателями оно как-то ложится ещё (потому что NULL pointer это буквально Option<>), а вот с числами мне это почему-то не нравится. Возможно я зануда.

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

Что сделал с сэкономленными байтами?

Для меня более короткий (в разумных пределах) код читается легче. Поэтому предпочитаю сокращать. И предпочитаю K&R стиль поэтому, тратить лишнюю строку на один символ это безобразие. Больше кода влезает на один экран, меньше скроллишь пустое место.

Вы еще не видели как я использую оператор запятая, дурной пример подхватил из кода OpenCV.

if (a) b = 1, c = 2;
jpegqs
()
Ответ на: комментарий от jpegqs

Случайно пишешь if (a) b = 1; c = 2; и у тебя отвратительный баг, проявляющийся раз в новолуние (если a обычно true).

Хотя если пользуешься автоматическим форматированием кода, то он перенесёт c = 2 на следующую строчку, тогда заметишь. Пользуешься ведь?

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