LINUX.ORG.RU

defer в C быть!

 ,


0

9

Привет, ЛОР!

Как я писал три года назад, в стандарт языка Си было предложено добавить выражение defer, выполняющее функцию или блок кода по выходу из области видимости, где оно было объявлено.

На днях данное предложение получило официальный статус и, скорее всего, defer появится в будущем стандарте C2y.

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

Ссылка на пост в блоге автора: https://thephd.dev/c2y-the-defer-technical-specification-its-time-go-go-go

Спецификация: https://thephd.dev/_vendor/future_cxx/technical%20specification/C%20-%20defer/C%20-%20defer%20Technical%20Specification.pdf

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

будет использовать arena/pool аллокацию, которая тоже не натягивается на концепцию RAII.

натягивается. делаете пустой деструктор (а только такой имеет смысл на этих ваших аренах), и усьо работает.

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

А ещё он любит Rust

а, помню-помню! Это тот негр, который хотел втащить статическую рефлексию в раст, написал в своей статье

Much like C, Rust perhaps a bit too heavily relies on (proc) macros and code generation techniques to avoid dealing with sincere deficiencies in the language, producing much heavier compile times by frontloading work at inappropriate compilation stages to offset the lack of language and library features

и его за это отменили в растоманской тусовке. Он получается в Си ушел? Одобряю и приветствую

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

Дефер в c++ не будет добавлен не потому, что он конфликтует с другими частями, а потому что это дикий костыль по сравнению с нормальной реализацией RAII.

А мне вот finally в С++ сильно не хватает, приходится костыли иногда лепить. Сабж это же аналог finally, я правильно понимаю?

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

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

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

Хотя, казалось бы, такую срань как C++ бустом уже точно не испортить.

Тащить в проект жирнобуст, это как киркорова в павлиньих перьях и короне. Ну и завязывать на буст проект, это сродни завязывания на GNU-измы как по мне.

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

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

то есть это как бы finally, но размазанный по блоку.

как конкретно в си предлагают - неохота и смотреть.

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

то есть это как бы finally, но размазанный по блоку.

Если использовать с умом, то может быть удобно наверное. Типа, при выделении каждого ресурса, рядом defer на освобождение, а в конце блока они все друг за другом освободятся.

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

Типа, при выделении каждого ресурса, рядом defer на освобождение, а в конце блока они все друг за другом освободятся.

угу, для этого и размазано.

alysnix ★★★
()

в стандарт языка Си было предложено добавить выражение defer, выполняющее функцию или блок кода по выходу из области видимости, где оно было объявлено

А есть реально полезное применение этому?

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

В C++ это делается через класс с деструктором и лямбду, так что специального функционала встроенного в язык не требуется:

void Do()
{
  scope_exit _([] {printf("-Do\n");});
  printf("+Do\n");
  printf("content\n");
}
X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от Loki13

Это полный аналог finally, просто блок финализатора располагается сверху, а не снизу. Что чаще всего имеет смысл, т.к. код освобождения ресурсов логически связан с кодом выделения ресурсов.

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

Всё ещё лучше чем свои костыли руками писать.

Буст-это такой же костыль, только чужой

Boost – это открытый и достаточно популярный набор библиотек.

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

Boost – это открытый и достаточно популярный набор библиотек.

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

slew
()
21 мая 2025 г.

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от Vic
1. Открыл файл.
2. Defer закрыть файл.
3. Делаешь с файлом еще что-то, не боясь, что забудешь закрыть или тебя выкинет и оно не закроется.

Вместо файла выбери любой другой ресурс.

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

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

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

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

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

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

ну, на нём ничего серьёзного и не пишут, тащемта

Весь Ozon на нем написан. Прежде чем начнется «это не серьезно» – это серьезнее 99.9% кода на C, который выглядит как «получили из прошивки сообщение и положили в структуру».

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

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

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

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

Вот где-где, а Си этого неявного поведения хоть жопой жуй.

а в каком языке явное поведение прям лезет через край?

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

Не все библиотеки одинаково полезны. Boost – это позор мира C++

Так C++ многое перенял у Boost. Чего вы темните? Так и скажите - «C++ - дрянь».

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

А как же сишное скрепное «никакого неявно выполняемого кода»?

Согласен, это нарушение этого принципа. С другой стороны функционал явно полезный и как сохранить пользу, не нарушая данный принцип - вопрос интересный…

Попробую на примере сформулировать проблему и подумать.

Как сейчас пишут:

int f(int x) {
  char *s = malloc(1);

  if (x == 0) {
    free(s);
    return 0;
  }

  free(s);
  return 1;
}

Как предлагается:

void f(int x) {
  char *s = malloc(1);
  defer free(s);

  if (x == 0) {
    // free(s);
    return 0;
  }

  // free(s);
  return 1;
}

Видим, что перед return неявно вставляется free(s).

Как этот код пишут «опытные» сишники:

int f(int x) {
  int result;

  char *s = malloc(1);

  if (x == 0) {
    result = 0;
    goto end;
  }

  result = 1;

end:
  free(s);

  return result;
}

У обоих подходов без defer есть очевидная проблема - никто не заставляет писать goto end. Можно написать return 0 и ничего не освободится.

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

Можно, к примеру, такой подход использовать:

int f(int x) {
  int result;

  char *s = malloc(1);
  must_visit free_s;

  if (x == 0) {
    result = 0;
    goto free_s;
  }

  result = 1;

free_s:
  free(s);

  return result;
}

По сути этот код идентичен предыдущему. Всё на 100% явно, никакого неявного кода или неявных переходов. Но тут есть конструкция must_visit <label>. По задумке эта конструкция заставляет компилятор верифицировать, что все пути выполнения программы после этой конструкции достигают указанной метки. Если написать return 0, то компилятор увидит, что в этом случае метка free_s будет недостижима и выдаст ошибку компиляции.

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

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

Как этот код пишут «опытные» сишники:


#define _autofree __attribute__((cleanup(_free)))

static _free(void **ptr) {
    free(*ptr);
}


bool function(void) {
    _autofree void *ptr = malloc(1);
    return !!ptr;
}
PPP328 ★★★★★
()
Ответ на: комментарий от vbr

Укажешь, где в стандарте языка C описан этот атрибут?

Радость моя, C без расширений никому не нужен. Он только в C23 более-менее подошел к точке, когда можно их не использовать. Начать можно с того что в стандарте C нет packed, без чего не работает ни одно ядро:

$ cd ~/src/linux
$ git grep __packed | wc -l
12274
gaylord
()
Последнее исправление: gaylord (всего исправлений: 2)
Ответ на: комментарий от vbr

Поддержки __attribute__((cleanup)) нет только в MSVC, но те кто на нём пишут прокляты, для кросскомпиляции есть mingw, который поддерживает. Все остальный мейджоры (gcc, clang, icc, скорее всего тонна других) поддерживают.

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

Это расширение практически всех компиляторов, кроме «особенного» msvc, который по ЕЕЕ вместо этого придумал __try/__except (для С, да)

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

Я проверил tcc - в нём этот атрибут игнорируется. Т.е. выше пример кода с утечкой, с чем вас и поздравляю.

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

А как же сишное скрепное «никакого неявно выполняемого кода»?

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

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

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

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

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

такое

Полезное, в смысле?

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

в нём нет никакого неявного поведения

LMAO. Напомнить тебе какие костыли придумываются для того чтобы это «отсутствующее» неявное поведение победить?


 (*) The compiler is within its rights to reorder memory accesses unless
     you tell it not to.  For example, consider the following interaction
     between process-level code and an interrupt handler:

	void process_level(void)
	{
		msg = get_message();
		flag = true;
	}

	void interrupt_handler(void)
	{
		if (flag)
			process_message(msg);
	}

     There is nothing to prevent the compiler from transforming
     process_level() to the following, in fact, this might well be a
     win for single-threaded code:

	void process_level(void)
	{
		flag = true;
		msg = get_message();
	}

     If the interrupt occurs between these two statement, then
     interrupt_handler() might be passed a garbled msg.  Use WRITE_ONCE()
     to prevent this as follows:

	void process_level(void)
	{
		WRITE_ONCE(msg, get_message());
		WRITE_ONCE(flag, true);
	}

	void interrupt_handler(void)
	{
		if (READ_ONCE(flag))
			process_message(READ_ONCE(msg));
	}

А теперь, не подглядывая в сорцы ядра, расскажи мне как выглядит реализация WRITE_ONCE().

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

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

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

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

Они не привозят, то, что мне нужно. А Ozon привозит.

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

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

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

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

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

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

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

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

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

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

Местные барыги делают буквально то же самое.

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

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

Iron_Bug ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)