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

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

int i=0; ((void*)i) — это NULL или нет?

mky ★★★★★
()

Неужели в C это появится раньше, чем в C++? (Да, в плюсах есть костыли, позволяющие добиться похожего эффекта, но это именно костыли.)

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

Я понял, Викторолегыч себя позиционировал как одного из тех троих, сразу после Пучкова-Гоблина.

Для справки: выливание помоев на интеллигенцию сегодня является одной из самых актуальных форм идейного обслуживания власть имущих. Зачем – описано у Ивана Антоновича в «Часе быка».

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

это именно костыли

Не соглашусь, это использование уже имеющихся возможностей языка и std без изменения самого языка. Вот смотри:

  1. P1260: Pattern Matching
  2. P1308: Pattern Matching
  3. P1371: Pattern Matching
  4. P2392: Pattern Matching using is and as
  5. И, наконец, Pattern Matching: match Expression, с реализацией: https://github.com/mpark/patterns. С которой можно делать так:
#include <cstdio>

#include <mpark/patterns.hpp>

void fizzbuzz() {
  using namespace mpark::patterns;
  for (int i = 1; i <= 100; ++i) {
    match(i % 3, i % 5)(
        pattern(0, 0) = [] { std::printf("fizzbuzz\n"); },
        pattern(0, _) = [] { std::printf("fizz\n"); },
        pattern(_, 0) = [] { std::printf("buzz\n"); },
        pattern(_, _) = [i] { std::printf("%d\n", i); });
  }
}

int main() {
  fizzbuzz();
}

Или так:

int factorial(int n) {
  using namespace mpark::patterns;
  return match(n)(pattern(0) = [] { return 1; },
                  pattern(_) = [n] { return n * factorial(n - 1); });
                  //      ^ wildcard
}

Или так:

std::string s = "large";

using namespace mpark::patterns;
match(s)(
    pattern(anyof("big", "large", "huge")) = [] { std::cout << "big!\n"; },
    pattern(anyof("little", "small", "tiny")) = [] { std::cout << "small.\n"; },
    pattern(_) = [] { std::cout << "unknown size.\n"; });

И т. д.

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

Костыли нужны для

Это не важно. Важно - есть или нет. Если нет, то любая эмуляция через - это "костыли". А летающие или ползающие - не имеет значения.

r--r--r--
()
Ответ на: комментарий от dataman

По поводу полёта C++, как только появляется критический для производительности блок программы, он выделяется в отдельную функцию и переписывается на Си. Вот эти отличные «паттерны» и прочие удобства C++ не помогают программе исполняться быстро.

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

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

Мягко говоря - неправда.

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

Если вы такой дичью занимаетесь, не надо обобщать и создавать у публики впечатление что это норма и все только так поступают.

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

А то что? Плюсовый код может обрастать интринзиками и асмовыми вставками, и это происходит сплошь и рядом. Для того чем мы занимаемся - перформансе это bread and butter что называется, но на Си никто ничего не переписывает, даже идей таких не возникает. Более того - лет 30 назад система была написана на голом Си и в процессе эволюции была переписана на плюсах. Вы что-то делаете не так.

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

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

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

А то что?

А то показываете себя с непрофессиональной стороны, как и топик стартер. Не нужно следовать плохому примеру.

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

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

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

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

Вы умный человек?

Смотря с кем сравнивать, всё в этом мире относительно.

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

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

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

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

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

Тем не менее, (void*)0, по мнению многих документаций, это вовсе не целочисленный ноль, стайпкастенный к указателю, а специальное синтаксическое выражение, обозначающее NULL. Чтобы гарантированно сделать стайпкастенный ноль (т.е. указатель на нулевой адрес) надо кастить не сам ноль, а переменную в которую этот ноль предварительно записан. На современных компиляторах/системах разницы нет (они представляют NULL как указатель на ноль, при этом разумеется коллективно нарушая ISO C стандарт, хотя почему-то толп возмущённых адептов ISO на эту тему не наблюдается), а вот на всяких древних (void*)0 могло означать совсем не нулевой адрес.

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

Обратимся к стандарту, скажем «ISO/IEC 9899:2026 (en) — N3783», страница 51.

An integer constant expression with the value 0, such an expression cast to type void *, or the
predefined constant nullptr is called a null pointer constant.^{57}) If a null pointer constant or a value of the type nullptr_t (which is necessarily the value nullptr) is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

Особенно важно второе предложение. Это как раз то утверждение, которое пытается донести господин @mkv до многих в этом обсуждении.

Интересно также пояснение по ссылке 57:

57) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.22.
VIT ★★
()
Ответ на: комментарий от mky

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

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

Это не я зациклен. Половина сишников в плюсы своего любимого языка записывают существование стандарта ISO. А его отсутствие – в минусы Rust.

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

Насрать что будет через 20-50 лет. Важно, что именно сейчас считать источником истины относительно языка. Ты не поверишь, но у компиляторов бывают баги, и вариант «код работает сегодня на таком-то компиляторе» совсем не означает, что код корректен, и ситуации, когда обновление компилятора даже на одну версию ломает код, случались даже в моей практике. При этом, баги в компиляторе я тоже ловил (и даже сообщал в багзиллу, и их потом чинили).

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

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

чо? Если у тебя строка не выровнена и при этом лежит в самом конце страницы, загребя данные после её конца ты получишь сегфолт. Не надо так делать.

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

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

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

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

У тебя уже есть! Ляянелле привет :3

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

Ну да, я ТСу заголовок чуть поправил, чтобы на 4.2 не походило :)

Из тебя паршивый журналист выйдет.

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

Тем не менее, (void*)0, по мнению многих документаций, это вовсе не целочисленный ноль, стайпкастенный к указателю, а специальное синтаксическое выражение, обозначающее NULL. Чтобы гарантированно сделать стайпкастенный ноль (т.е. указатель на нулевой адрес) надо кастить не сам ноль, а переменную в которую этот ноль предварительно записан.

Нет, это тоже не работает.

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

На современных компиляторах/системах разницы нет (они представляют NULL как указатель на ноль

Чё несёт…

при этом разумеется коллективно нарушая ISO C стандарт,

В какой букве?

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

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

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

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

учись читать.

Ты сначала писать научись.

они представляют NULL как указатель на ноль

int zero = 0;
void *p = &zero;

p - указатель на ноль. Но p - это не NULL.

при этом разумеется коллективно нарушая ISO C стандарт,

То есть никаких нарушений нет, а ты, как обычно, пустозвонишь.

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

Ты специально клоунаду разводишь или реально не понял что значит «указатель на ноль»? Если первое - иди нафиг, если второе - сходи на уроки русского языка в школу.

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

реально не понял что значит «указатель на ноль»?

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

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

Тем не менее, (void*)0, по мнению многих документаций

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

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

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

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

Ты же понимаешь что твои абсракции и прочие извращения не имеют отношения к тому как всё устроено? А шланг - вообще говно. Шланг среди компиляторов - типа хрома среди браузеров. Такое же отвратительное поделие.

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

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

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

Ссылка лагает, но если какой-то компилятор вычисляет i=0,(void*)i как асбтрактный NULL то компилятор значит с багом.

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

вывел из этого заблуждения какой-то абсурд

Какой?

если какой-то компилятор вычисляет i=0,(void*)i как асбтрактный NULL то компилятор значит с багом.

Ночь откровений на лоре.

Ну и чему же

intptr_t i = 0;

void *p = (void *) i;

должен быть равен p?

P.S.

С тебя ещё несоответствия стандарту.

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

Rust

Вроде, минусом было не отсутствие стандарта, а отсутствие альтернативных реализаций. И там сложно сказать, что из чего вытекает — нет альтернатив так как нет стандарта, или нет стандарта, так как нет необходимости приводить альтернативные реализации под более-менее один знаменатель. Но я не хочу тут Rust срач устраивать.

Ты не поверишь

Я не поверю? Я знаю, что у NDP-фортрана, который стоил $10k были баги, и багзилы не было. Но он иногда давал код заметно быстрее MS Fortran PS, поэтому как-то грызли кактус.

UB – это отстрел жопы, просто какие-то из них компиляторы научились статически распознавать, для каких-то требуется ubsan, а какие-то выстрелят лет через 10

Насрать что будет через 20-50 лет

Не понял, то есть важно, что будет через 10 лет, а не через 20?

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

И из этого вы сделали вывод, что нужно писать код в строго соответствии ISO стандарту, даже если полученый код не работает на данной версии компилятора/железа?

Помню, был у нас в прошлом веке один эникейшик-кодер-каратист. Он 6 или 9 месяцев писал какую-то фигню, типа просмотр результатов расчёта (поле температур, скоростей и т.д.), естественно под MS DOS. А потом заявил, что его программа без ошибок, а вот графическая библиотека кривая, с ошибками, поэтому его программа работать не будет. Ну все поулыбались и разошлись, что-то доказывать IRL не стали, так как удар у него был поставлен :)

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

Особенно важно второе предложение.

И, если это дальше смотреть, то получается, что когда операционка делает недоступной (page fault, segmentation fault) нулевую страницу, она, как бы, приводит NULL-указателель, выбранный компилятором равным 0x00000000, к требованиям стандарта. То есть не компилятор спрашивает у ОС какое значение можно для NULL-указателя, а ОС подстраивается под компилятор, так, что-ли... И, если компилятор решит исползовать для NULL какое-то другое значение (у которого не все биты нулевые), то ОС, загрузчик, etc никак об этом не узнают.

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

в предположении что NULL это (void*)0

Нет, компилятор Си никогда не знал, что есть слово NULL, всегда препроцессор скармливал ему ((void*)0), или ((char *)0), так как void не сразу появился. С другим численным значением делали не NULL, а именно ((void*)0). При этом параллельно с развитием Си, в других ЯП NIL/NULL были ключевым словом/встроенной функцией, возможно от этого там легче заходило, что NULL может не указывать на адрес 0x000000. И, возможно, именно по влиянием других ЯП, в Си пытались затащить «не нулевой NULL».

Затем те архитектуры ушли в прошлое

И архитектуры, и те древние компиляторы, типа PL/I.

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

С свмого начала и до сих пор есть куча архитектур где RAM начинается с 0, а reset vector вообще в другое место. А ещё гарвардская архитектура, где без (void*)0 вообще никак.

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

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

нужен «невалидный адрес»

Невалидный не в плане, что аппаратно туда нельзя обращаться, а в плане, что там нет ОЗУ, следовательно валидный указатель на данные/код не может туда показывать. То есть валидный указатель, полученный от malloc или от операции взятия адреса переменной не должен совпасть по значению с NULL-указателем. Это толкование порождения всяких теоретиков, а не мое требование, если что.

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

то компилятор значит с багом

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

Ссылка лагает

#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main(void) {
    intptr_t i = 0;
    char *ptr = (char*)i;

    strcpy(ptr, "hello LOR!");
    printf("%s\n", ptr);
}

************

Program returned: 139
Program stderr
Program terminated with signal: SIGSEGV
mky ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.