LINUX.ORG.RU

В Си предложили добавить switch-case для строк

 , ,


0

3

Привет, чат!

Спустя много лет, в язык Си наконец предложено добавить возможность использовать выражение switch-case для строк. Например, можно будет писать вот такое:

const char *s = get_some_string();

switch(s) {
case "this":
  handle_this();
  break;
case "that":
  handle_that();
  break;
default:
  handle_other();
  break;
}

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

Ссылка на предложение: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3895.pdf



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

А нулик точно в конце строки? А если его чем-то перепишут и нулик окажется в другом месте? А если его вообще не будет? А как узнать длину строки: каждый раз перебирать символы, пока не нулик?

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

Я так и понял, что что то го-специфичное. Я с го почти не работал. По ощущениям это такой раст, но со сборщиком и менее удобный. Я и забил.

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

Непарные кавычки - это никакое не UB, а синтаксическая ошибка.

Почитай стандарт языка, мы о нём говорим. С точки зрения стандарта это UB. Нет, я не шучу. Вот цитата:

(26) An unmatched ’ or " character is encountered on a logical source line during tokenization (6.4)

из списка UB

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

Я правильно понимаю, что вы не против length-based строк как концепции, а против конкретного паттерна реализации?

Ну да. Я совершенно не против length-based строк. Это весьма древний и достаточно часто используемый и по сей день вариант, например, при обмене данными с периферией, когда первый байт строки (или несколько первых байт) это её длина.

Когда реальная строка расположена отдельно от её метаданных.

Не только. Я уже пытался объяснить, что если уж переизобретать строку, то строка как тип данных должна быть базовым, монолитным типом компилятора, в точности как float/double, при сохранении всех фич ASCIIZ включая адресную арифметику и обычный malloc/free для аллокации, а не вот это вот всё.

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

А нулик точно в конце строки?

Да.

А если его чем-то перепишут и нулик окажется в другом месте?

Именно так и обрезают строки - помещая нулик в другое место.

А если его вообще не будет?

Это будет бесконечная строка занимающая всю оставшуюся память начиная с её адреса.

А как узнать длину строки: каждый раз перебирать символы, пока не нулик?

Длина строки в 99.999% случаев нужна чтобы перебрать всю строку по символу. Поэтому никакой разницы при этом переборе нет - сравнивать индекс с длиной или текущий символ с нуликом нет вообще.

в 0.0001% прочих случаев длину строки требуется посчитать всего один раз.

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

в 0.0001% прочих случаев длину строки требуется посчитать всего один раз.

Свежо предание, но верится с трудом…

Если бы это было правда, то всех этих плясок с сохранением длины строки совместно со строкой и обновлением длины при каждой операции никто бы не делал. Ради одной десятитысячной процента случаев вопрос о длине строки даже не дошёл бы до необходимости функции strlen. Думаю, вы сильно недооцениваете частоту использования, а поэтому и просадку производительности, этой операции.

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

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

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

Длина строки в 99.999% случаев нужна чтобы перебрать всю строку по символу.

Нет. Длина строки чаще всего нужна чтобы выделить под неё память, как например это делают strcat, asprintf и прочие. Копирование при этом на современных чипах происходит не посимвольно.

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

Длина строки в 99.999% случаев нужна чтобы перебрать всю строку по символу.

Нет. Длина строки чаще всего нужна чтобы выделить под неё память, как например это делают strcat, asprintf и прочие. Копирование при этом на современных чипах происходит не посимвольно.

strcat

strdup, простите.

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

поидее в тех блочках(sse4.2,avx2-512) тоже флаги нуля нужны, берём любой интринсик и там нужна маска или искомых или сравнимых. без нуля поидее как не крути.

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

поидее в тех блочках(sse4.2,avx2-512) тоже флаги нуля нужны, берём любой интринсик и там нужна маска или искомых или сравнимых. без нуля поидее как не крути.

Зачем? Если у тебя есть длина, ты заранее знаешь сколько полноценных итераций на SIMD делать. Побайтово потом только хвост надо скопировать. Копировать через SIMD всю строку, проверяя на ноль, грозит тебе выходом за границы массива, если размер строки не кратен размеру блока. Не надо так делать.

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

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

Тем не менее, это очень платформо-специфично и заранее может быть очевидно, что если нет FPU и даже умножения, то это вызовет проблемы для freestanding.

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

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

Да тупо все сколько-нибудь современные хэш-функции принимают pointer-and-length, а не нуль-терминированные строки. Потому что затратно слишком проверять байты на ноль, так ещё и две копии делать. А дёргать strlen, а потом хэш-функцию — конечно, медленнее.

Но я не понимаю, зачем вы спорите с этим маразматиком.

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

Да тупо все сколько-нибудь современные хэш-функции принимают pointer-and-length, а не нуль-терминированные строки. Потому что затратно слишком проверять байты на ноль, так ещё и две копии делать

Хэш функции требуют, чтобы размер входных данных был кратен размеру блока. Для строк это не так.

Но я не понимаю, зачем вы спорите с этим маразматиком.

Это ЛОР. В данный момент единственная функция этого форума – сраться с шизофрениками. Для каких-то других целей этот форум абсолютно бесполезен.

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

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

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

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

А switch case со строками повсюду будет требовать отдельного кода для работы с подстроками.

Нахрена? Тут уже восьмую страницу форума идёт срач о функции длиной в пять строчек. Вот, держи копию из glibc:


int strcmp (const char *p1, const char *p2)
{
  register const unsigned char *s1 = (const unsigned char *) p1;
  register const unsigned char *s2 = (const unsigned char *) p2;
  unsigned reg_char c1, c2;

  do
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0')
	return c1 - c2;
    }
  while (c1 == c2);

  return c1 - c2;
}

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

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

Статус простого языка сишечка потеряла лет 30 назад, если не больше. Реализация современного стандарта с нужными для быстрой работы кода оптимизациями – это минимум сотня-две тысяч строк кода. Тот же Kefir, автор которого кстати тут зависал, это 170к строк на Си, не считая тестов (с тестами 300к). И это просто хобби-проект, не особо претендующий на статус полноценной реализации и поддерживающий всего одну аппаратную архитектуру. Если брать gcc и шланг, там выходит уже ближе к миллиону строк.

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

к какой категории вы относите себя,

К любителям странного. У меня вообще достаточно интересные хобби.

можно ли это считать за признание самоцели флуда

Что такое «самоцель»? Целью моих вбросов тут является запуск интересной дискуссии с множеством участников, в рамках которой я мог бы натолкнуться на какие-то интересные мысли. Плюс, мне нравится ощущение власти, рождающееся из моей способности заставить ненулевое количество участников этого форума потратить свои силы и время на генерацию зачастую достаточно шизофреничных комментариев. Разве не для этого форумы существуют? Кам он!

а что собственно делать с абсолютно кликбейтным заголовком этого треда и контентом который мягко говоря 4.2??

Что делать кому? Тебе? Понятия не имею. Ты можешь либо прокомментировать, либо пройти мимо. Ты, судя по всему, выбрал первое.

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

Целью моих вбросов

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

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

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

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

Чтобы ты не говорил, что длину специально узнавать не надо, но ты упускаешь, что длину бывает надо знать до обработки строки. Вот тебе простейшие примеры, вызывающие тормоза без подпорок с отдельными счетчиками длин и индексами:

1) Надо strcat нескольким строкам сделать. В лоб стандартным образом это будет считай O(N^2) .

2) Сравнение строк с конца, поиск суффиксов. Например, быстро проверить имя файла на нужное расширение. Если заранее не знать длины строки, то это O(N), если знать, то O(1).

3) Парсинг чего-то. Надо постоянно создавать подстроки и передавать в другие функции. В итоге или временно модифицируем исходный буфер (что потоконебезопасно и портит данные), либо на каждом шаге дрочиться с malloc+strncpy для выделения кусочков. А для strncpy опять нужно знать размеры, что приводит к лавинообразному росту вызовов сканирования памяти. Или таки обрастает вся работа лишними индексами и счётчиками.

4) Пакетная обработка с SIMD-инструкциями. Если заранее известен размер строки её можно сразу пачками (до 64 байт у AVX512) раскидать по регистрам.

P.S. И это я ещё про потенциальные ошибки безопасности с буфером молчу.

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

это про какую кодировку речь?

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

Хэш функции требуют, чтобы размер входных данных был кратен размеру блока. Для строк это не так.

При всём желании не могу понять, что вы тут понаписали. Давайте так:

1. «Хэш-функции» в вашем понимании это что? SHA-1, FNV-2, CRC32, Murmur3_32 — что из этого является хэш-функциями?

2. Какого ещё блока? Какой блок у FNV-2?

3. Получается, «хэш-функции» от «строк» вообще нельзя считать? Или под «строками» вы имеете в виду сишные строки?

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

Вот, держи копию из glibc:

Ой, кто-то совсем не шарит.

~/repo/glibc$ find sysdeps/x86_64 -iname '*strcmp*.s' | xargs wc -l
  1784 sysdeps/x86_64/multiarch/strcmp-sse4_2.S
     9 sysdeps/x86_64/multiarch/strcmp-avx2-rtm.S
    18 sysdeps/x86_64/multiarch/rtld-strcmp.S
   221 sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S
  1320 sysdeps/x86_64/multiarch/strcmp-avx2.S
  1600 sysdeps/x86_64/multiarch/strcmp-evex.S
  2160 sysdeps/x86_64/multiarch/strcmp-sse2.S
    31 sysdeps/x86_64/strcmp.S
  7143 total
~/repo/glibc$ 
shdown ★★
()
Ответ на: комментарий от yorshka

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

Как бы если есть некоторая строка, то под неё уже выделена какая-то память, внезапно. :) Кто-то мешает посмотреть сколько выделено? Кроме того, если строка в этой памяти появилась, то кто-то её наверно туда поместил, и в процессе помещения строки туда опять же нет проблем и особых накладных расходов посчитать её длину если нужно.

как например это делают strcat,

strcat ничего не выделяет.

Копирование при этом на современных чипах происходит не посимвольно.

И поиск нулевого байта тоже.

Stanson ★★★★★
()
Ответ на: комментарий от shdown
  1. Какого ещё блока? Какой блок у FNV-2?

Окей, есть хеш-функции с блоком в 1 байт. Но это не общий случай.

  1. Получается, «хэш-функции» от «строк» вообще нельзя считать?

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

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

Ой, кто-то совсем не шарит.

Кто-то шарит, но это всё уже не столь обязательные изыски. В минимальном варианте там 5 строк, которые я привёл.

Алсо, мне нравится, что тут шутка в том, что, как уже писали выше, даже если ты руками напишешь strcmp(), тот же gcc вставит одну из реализаций выше. Так что ты этот код себе получишь в любом случае.

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

Как бы если есть некоторая строка, то под неё уже выделена какая-то память, внезапно. :)

Внезапно её может потребоваться скопировать куда-то или что-то с ней сделать.

Кто-то мешает посмотреть сколько выделено?

Где посмотреть?

strcat ничего не выделяет.

В Си предложили добавить switch-case для строк (комментарий)

Копирование при этом на современных чипах происходит не посимвольно.

И поиск нулевого байта тоже.

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

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

Нахрена? Тут уже восьмую страницу форума идёт срач о функции длиной в пять строчек. Вот, держи копию из glibc:

Ещё раз совсем кратко. В Си есть принцип не делать неявных действий. Как бы не единственное до сих пор исключение - это эмуляция FPU и прочих арифметических операций при их отсутствии. И то, если это не freestanding.

Даже приведённый код, хотя и простой, но не позволит выполнять switch case за константное время, как сейчас. Возникает ещё и проблема кодировок.

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

А ещё с твоей функцией из glibc, если её применять для switch case возникают потенциальные проблемы безопасности:

1) Timing Attack для секретных данных из-за того, что время switch case начинает явно зависеть от исходных данных.

2) Перекладывание проверки на NULL с программиста на компилятор в неочевидном месте. Может произойти разыменование NULL, если в ключ попадает исходная строка.

3) Классическое чтение за пределами буфера, если в switch почему-то попало что-то без '\0' (впрочем, это постоянно вылезает с zero).

Статус простого языка сишечка потеряла лет 30 назад, если не больше. Реализация современного стандарта с нужными для быстрой работы кода оптимизациями – это минимум сотня-две тысяч строк кода.

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

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

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

Тебе написать простой бенчмарк с классическими Си-строками и структурой с String из char* и len, чтобы ты увидел, что строки сливают по быстродействию? Твой подход требует не просто со строками работать, записывая нужный код, а каждый раз думать как там длина вычисляется и используется.

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

проверить имя файла на нужное расширение.

А, понятно, вендузятники рассуждают про программирование. :) Расширение, жёваный крот. :)

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

Забавно, но strcat вообще-то редко испольуемая функция. :) В основном её испольуют всякие жабомакаки и пр. когда им надо "строка1" + str2 + "строка3" сделать. Ну привыкли они так писать.

И самое главное - я вообще не вижу никаких проблем в использовании строк типа «длина;текст» и аналогичных, если это базовый и монолитный тип компилятора, и если с этими строками можно обращаться точно так же как c ASCIIZ и не требуется плясок и извращений если мне вздумается что-то типа char* s = str+10; использовать и без лишних телодвижений передавать строку туда где предполагается произвольный набор байт типа write() и send(). Я вижу проблемы исключительно в уродливых костылях, типа той же std::string, которые сделаны через жопу.

Хотите замеить ASCIIZ на строку с длиной в сишечке - не вопрос вообще, только делайте её нормлаьно, блин, а не городите эти ублюдочные костыли типа std::string со структурками, специальными функциями на каждый чих и прочую бредятину. И да, нолик в конце всё равно оставьте, пригодится.

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

Ещё раз совсем кратко. В Си есть принцип не делать неявных действий.

Нет такого принципа. Компиляторы ему уж точно не следуют.

Даже приведённый код, хотя и простой, но не позволит выполнять switch case за константное время, как сейчас.

Switch-case не выполняется за константное время. Время выполнения switch-case зависит от того, насколько далеко от начала таблицы находится совпадающее с входным значение. В лучшем случае у тебя будет логарифмическая сложность.

  1. Timing Attack для секретных данных из-за того, что время switch case начинает явно зависеть от исходных данных.

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

Перекладывание проверки на NULL с программиста на компилятор в неочевидном месте.

Что тут неочевидного? Буквально написано в предложении, что в случае NULL выполняется default. Не нравится? Не суй NULL.

  1. Классическое чтение за пределами буфера, если в switch почему-то попало что-то без ‘\0’ (впрочем, это постоянно вылезает с zero).

Сишники должны страдать. Тут ничего не поделаешь.

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

Ну лол же ну…

gcc там вставил не один, а АЖ ДВА ВЫЗОВА STRLEN! Видимо, чтобы совсем сишников посрамить и вставить им неявных вызовов поглубже.

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

Тебе написать простой бенчмарк с классическими Си-строками и структурой с String из char* и len, чтобы ты увидел, что строки сливают по быстродействию?

Я тоже могу написать аналогичный бенчмарк который покажет что твой String сливает ASCIIZ по быстродействию и ужору памяти.

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

А, понятно, вендузятники рассуждают про программирование. :) Расширение, жёваный крот. :)

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

Забавно, но strcat вообще-то редко испольуемая функция. :) В основном её испольуют всякие жабомакаки и пр. когда им надо «строка1» + str2 + «строка3» сделать. Ну привыкли они так писать.

Да при всякого рода парсинге типичная операция. Ну вот такие прекрасные в Си строки с null, что ещё надо с правильным подходом писать.

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

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

typedef struct
{
    char* data;
    size_t len;
} String;

а не просто сишные строки. Причём data в этой структуре совсем уже не обязательно с '\0' на конце, хотя в этом случае лучше избегать литералов в коде. Так что, да нолик может пригодиться.

Я вижу проблемы исключительно в уродливых костылях, типа той же std::string, которые сделаны через жопу.

Всё это не понадобилось бы, если бы не null terminated у Ритчи с Томпсоном и Керниганом. То что в 70-е было изящным, сейчас кучу проблем вызывает.

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

Нет такого принципа. Компиляторы ему уж точно не следуют.

Следуют. По крайней мере, если без оптимизатора. В твоём примере, это оптимизатор слишком умный оказался. С -O0 strlen() ни разу не вызывается. Ну так оптимизаторы на то и оптимизаторы, чтобы всякую дичь творить, если им кажется, что она ускорит работу.

Что тут неочевидного? Буквально написано в предложении, что в случае NULL выполняется default. Не нравится? Не суй NULL.

Там компилятору что-то придётся делать с разыменованием, а не просто в default сваливать (которого может и не быть).

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

Я тоже могу написать аналогичный бенчмарк который покажет что твой String сливает ASCIIZ по быстродействию и ужору памяти.

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

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

Не вставляет gcc :(

А без -fno-builtin понимает, что это strcmp и просто вставляет call.

$ cat foo.c
#include <stddef.h>

size_t myfunc(const char *s)
{
    size_t i = 0;
    while (s[i]) { ++i; }
    return i;
}
$ gcc -Wall -Wextra -O3 -fno-builtin -S foo.c -o /dev/stdout
	.file	"foo.c"
	.text
	.p2align 4
	.globl	myfunc
	.type	myfunc, @function
myfunc:
.LFB0:
	.cfi_startproc
	xorl	%eax, %eax
	cmpb	$0, (%rdi)
	je	.L4
	.p2align 4
	.p2align 4
	.p2align 3
.L3:
	addq	$1, %rax
	cmpb	$0, (%rdi,%rax)
	jne	.L3
	ret
	.p2align 4,,10
	.p2align 3
.L4:
	ret
	.cfi_endproc
.LFE0:
	.size	myfunc, .-myfunc
	.ident	"GCC: (Debian 15.2.0-17) 15.2.0"
	.section	.note.GNU-stack,"",@progbits
$
shdown ★★
()
Ответ на: комментарий от anonymous_incognito

Нет такого принципа. Компиляторы ему уж точно не следуют.

Следуют. По крайней мере, если без оптимизатора.

Чо? Без оптимизатора Сишечка никому нахрен не всралась.

В твоём примере, это оптимизатор слишком умный оказался. С -O0 strlen() ни разу не вызывается. Ну так оптимизаторы на то и оптимизаторы, чтобы всякую дичь творить, если им кажется, что она ускорит работу.

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

Что тут неочевидного? Буквально написано в предложении, что в случае NULL выполняется default. Не нравится? Не суй NULL.

Там компилятору что-то придётся делать с разыменованием, а не просто в default сваливать (которого может и не быть).

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

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

Разыменование NULL в сишечке является неопределённым поведением.

Чего? В твойм манямикре, по адресу 0 нынче астрал, что-ли? :) NULL - это такой же адрес как и все остальные. Просто он редко используется для пользовательских данных, только и всего. А там может быть дофига разного - от вектора прерываний, который надо туда сначала записать, если это RAM, до самой обычной памяти.

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

В твойм манямикре

Не в его, а в мирке разработчиков стандарта Си:

the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

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

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

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

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

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

Ещё как может. Поскольку сегментные ограничения в современных ОС не используются, минимальный шаг изменения доступности памяти - 4096 байт. Можно искать нули хоть пачками по 4КБ (предварительно выровняв позицию на границу), но для такого нет подходящих инструкций. А вот по 4-8 байт - вполне.

И сразу заранее уточню:

1) на мнение ISO по этому поводу плевать, я описал то что будет работать на реальном железе

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

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

Какие ещё текстовые константы? Если ты про предложение про которое эта тема, то его никто рассматривать не собирается.

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

В итоге программирование на этом говноязычке превращается в квест «на%:и компилятор», чтобы он правильный бинарник тебе сгенерил.

Как-то вы зациклены на этой мысле. Назовите ЯП, у которого куча стандартов и куча компиляторов, реализующих эти стандарты, но при этом сложный код, соответствующий стандарту, идентично выполняется независимо от компилятора, ОС, железа.

И, главное, как бы в не переживали за Си или другой ЯП, написаный вами сейчас код, идеально соответствующий стандарту, лет через 20-50 кто-то его будет разгребать. И поминать добрым словом это легаси гогно и чудака это написавшего :)

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

Почему «будет», копиляторы давно знают про этом и используют оптизимированый strlen.

А вот по 4-8 байт - вполне.

И дальше, SSE2, SSE4.2, реализовано по 16 и 32 байта.

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

Почему «будет», копиляторы давно знают про этом и используют оптизимированый strlen.

Нет. Оптимизированные strlen написаны на ассемблере, а не на Си. Компиляторы не умеют сами оптимизировать циклы, эквивалентные strlen (см. В Си предложили добавить switch-case для строк (комментарий)), умеют только заменять на вызов функции strlen из стандартной библиотеки (которая в glibc написана на ассемблере).

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

Непонял, откуда вылезло, что strlen должна быть реализована на Си, особенно с учётом, что тема про новый вариант switch case, он тоже должен быть без ассембелера?

Но так, есть такое https://github.com/bminor/glibc/blob/master/string/strlen.c:

size_t
__strlen (const char *str)
{
  /* Align pointer to sizeof op_t.  */
  const uintptr_t s_int = (uintptr_t) str;
  const op_t *word_ptr = (const op_t*) PTR_ALIGN_DOWN (str, sizeof (op_t));

  op_t word = *word_ptr;
  find_t mask = shift_find (find_zero_all (word), s_int);
  if (mask != 0)
    return index_first (mask);

  do
    word = *++word_ptr;
  while (! has_zero (word));

  return ((const char *) word_ptr) + index_first_zero (word) - str;
}

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

NULL это (void*)0 и ничего более. Абсолютно валидный адрес. Свои фантазии о каких-то там абсракциях и прочий бред не относящийся к реальности можешь оставить при себе.

Stanson ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.