Зачем использовать функции GLib?
При программировании на C и GTK+ почему "лучше" использовать g_strdup_printf
, g_free
, g_strcmp0
и т. д. и другие функции GLib?
7 ответов
В общем, целью GLib является библиотека утилит и переносимости. Это само по себе является причиной, чтобы рассмотреть возможность его использования.
Все конкретные функции, о которых вы упомянули, предлагают что-то дополнительное в дополнение к их вариантам стандартной библиотеки C:
g_strdup_printf
какsprintf
, но фактически выделяет буфер для вас и избавляет вас от догадок о том, насколько большим должен быть буфер. (Возвращаемое значение должно бытьg_free
D").g_free
какfree
, но проверяет NULL-указатель.g_strcmp0
какstrcmp
, но обрабатывает NULL-указатель как пустую строку и таким образом сортирует его впереди.
Для согласованного поведения в нескольких операционных системах. Это вещь портативности.
В некоторых других средах Unix, кроме Linux, или если ваша программа скомпилирована в Windows, некоторые из этих функций могут не существовать или работать по-разному в целевой операционной системе.
Использование версий glib обеспечивает согласованное поведение.
GLib обеспечивает переносимость и основные вещи, которые вы ожидаете в настоящее время от любого языка программирования, такие как типы коллекций (связанные списки, массивы, хеш-таблицы и т. Д.). Вот некоторые из преимуществ, которые GLib может дать вам.
портативность
Смысл GLib в том, чтобы быть переносимым не на стандарт C, а на реализацию стандарта. GLib заботится об известных причудах, которые на первый взгляд могут показаться бесполезными, пока вам не понадобится перенести код на платформу с такими неприятными ошибками.
Давайте возьмем пример g_free
Многие критикуют это. Есть платформы, где free(NULL)
потерпит неудачу, даже если C99 говорит, что это должно работать. Эта проверка существует как минимум с 1998 года (я отслеживал ее в истории git). Некоторые могут сказать, что это больше не нужно, но даже в 2017 году я работал в компании, которая проверяетNULL
перед звонкомfree
потому что в противном случае он завис бы на их встроенной платформе. Он также служит оболочкой для внедрения вашего кода, когда вы хотите выполнить серьезную отладку памяти.
читабельность
Это помогает улучшить читабельность вашего кода, предоставляя некоторые функции-обертки, которые не только улучшают переносимость, но и помогают избежать многих языковых ошибок. Кто из вас тестирует malloc
чтобы увидеть, вернется ли онNULL
? У скольких из вас есть способ восстановиться, если он вернетсяNULL
, так как у тебя в основном не хватает памяти?
g_malloc
прервет приложение, если оно не может выделить то, что вы хотите, и во многих приложениях это именно то поведение, которое вы хотите. Для очень больших выделений, которые могут потерпеть неудачу, у вас естьg_try_malloc
, Это то же самое, что и malloc, но, тем не менее, дает вам преимущество в качестве обертки, которую можно использовать для инструментовки.
Будучи в состоянии написать:
char *buffer = g_malloc(30);
/* Do something with it ... */
g_free (buffer);
... освобождает разум и позволяет разработчику сосредоточиться на задаче, которую она пытается достичь. Это также позволяет избежать сбоя вашей программы намного позже, потому что она пытается писать, используяNULL
указатель, и вы должны отслеживать распределение.
Стандартная библиотека C полна ловушек, и отсутствие микроуправления каждой строкой кода, которую вы пишете, является облегчением. Просто прочитайте раздел ошибок на страницах руководства для некоторых функций, и вы увидите. Наличие меньшего количества стандартного кода для проверки ошибок делает код более простым для чтения, что повышает удобство сопровождения и вызывает меньше ошибок.
Характеристики
Другой момент - целая куча типов коллекций, которые предоставляет GLib, и что вам не нужно переопределять. То, что переопределение связанного списка легко, не означает, что вы должны это делать. Я работал в другой компании, которая поставляла код с несколькими реализациями связанных списков, потому что некоторые разработчики просто имели бы синдром " Не изобретено здесь" и перерабатывали свои собственные. Обычная, тщательно проверенная, широко распространенная библиотека, такая как GLib, помогает избежать этой чепухи. Вы не должны перестраивать этот материал, если у вас нет особых ограничений производительности.
Их поведение четко определено на любой платформе, поддерживаемой GTK+, в отличие от встроенных функций, которые иногда могут работать частично.
Я должен сказать, что это хорошо задумано, но не очень хорошо выполнено. Очень приятно, что ваша программа не будет аварийно завершать работу, если вы попытаетесь освободить () указатель более одного раза. Или сортируйте пустую строку. Но это смешанное благословение. Он также не позволяет вам обнаружить эти неприятные ошибки в вашем коде. Вам не только будет трудно портировать вашу программу в один прекрасный день, потому что вы полагаетесь на нестандартные функции, вам также будет очень трудно, потому что ваш код содержит ошибки и вы никогда не узнаете.
10 лет назад использование библиотеки Gnome могло иметь смысл, но теперь это наследство. C89, пожалуй, самый стандартный язык в мире, с очень стабильными функциями и синтаксисом, поэтому отладка чужого кода C89 выполнима.
В отличие от этого, glib Gnome изменяет функции своей функции вне стандарта C, поэтому вы не только сталкиваетесь с отладкой неясного кода-обертки, созданного на C, но и ваш код может перестать работать, потому что Gnome меняет свои функции-обертки.
Приложение A: g_snprintf()
Более безопасная форма стандартной функции sprintf(). Гарантируется, что вывод не будет превышать n символов (включая завершающий нулевой символ), поэтому легко гарантировать, что переполнение буфера не произойдет.
Смотрите также g_strdup_printf().
В версиях GLib, предшествующих 1.2.3, эта функция может возвращать -1, если выходные данные были усечены, и усеченная строка может не заканчиваться нулем. В версиях до 1.3.12 эта функция возвращает длину выходной строки.
Возвращаемое значение g_snprintf () соответствует функции snprintf(), стандартизированной в ISO C99. Обратите внимание, что это отличается от традиционного snprintf(), который возвращает длину выходной строки.
Строка формата может содержать позиционные параметры, как указано в Спецификации Single Unix.
Я менее взволнован тем, что могу написать (еще один) связанный список, чтобы заменить Gnome, и еще одну версию snprintf () и кучу дрянного кода-обертки, который тихо использует память malloc(), тем самым нарушая один абсолютный максимум C-кодирования: "всегда malloc() и free() в одной и той же области видимости", чтобы заменить g_strdup_printf().
g_strdup_printf ()
Аналогична стандартной функции C sprintf(), но более безопасна, поскольку она рассчитывает максимальное требуемое пространство и выделяет память для хранения результата. Возвращаемая строка должна быть освобождена с помощью g_free(), когда она больше не нужна.
Добавьте к этому волнение от огромного количества строковых изменений в коде для выполнения "полезных" вещей, таких как изменение gchar на char, gint на int, gboolean на bool и т. Д. И т. Д. И т. Д., До тошноты, пока мои сравнения Subversion не станут телефонная книга. Хуже того, в конечном итоге вам придется менять все больше и больше кода, потому что этот материал забросан по всем файлам.h, поэтому он продолжает разрастаться, как упавший на воду труп, в огромный беспорядок.
Если вы ищете работу по контракту и где-нибудь видите glib.h, БЕГИТЕ!!! Просто сказать нет!.
PS: Скачивая исходный код, удаляя все специфичные для Gnome типы, и перекомпилируйте его, чтобы сделать свои собственные "g_"- функции вроде бы не такими, вроде как работает, и это значительно экономит время.
Приложение B: g_strdup_printf()
Более ужасный гном Crappola из Гнома. В Gnome есть множество "прекрасных" функций, таких как g_strdup_vprintf(), которые "волшебным образом" знают, сколько памяти нужно для хранения возвращаемой строки, и у меня была возможность заглянуть за "магию". Это выигрывает мою награду за самое отвратительное злоупотребление С когда-либо.
Если вы продолжаете отслеживать g_strdup_vprintf() через все функции-оболочки, вы попадаете в этот гем в gmessages.c....
/**
* g_printf_string_upper_bound:
* @format: the format string. See the printf() documentation
* @args: the parameters to be inserted into the format string
*
* Calculates the maximum space needed to store the output
* of the sprintf() function.
*
* Returns: the maximum space needed to store the formatted string
*/
gsize
g_printf_string_upper_bound (const gchar *format,
va_list args)
{
gchar c;
return _g_vsnprintf (&c, 1, format, args) + 1;
}
ЛЮБАЯ функция printf () не только медленнее, чем snot при абсолютном нуле, вы заметите, что они выделяют целый байт, yup, весь gchar c для хранения, что гарантирует переполнение, но тогда кого это волнует? они получают длину строки, которая им понадобится для malloc() - потому что они собираются развернуться и снова выполнить весь printf () - на этот раз "волшебным образом" с достаточным объемом памяти.
Конечно, они прибавят +1 к размеру, так что у вас будет место для nul-терминатора, гарантировано, конечно, за ужасную цену, но они спрятали это так глубоко в коде, что ставят на вас " Я просто сдамся и использую его вслепую и не замечу, что это за огромный пердеж. Спасибки, ребята. Я просто люблю свой код для сканирования.
Не позволяйте функции _g_vsnprintf() отбросить вас, потому что в gprintfint.h вы обнаружите, что маленький драгоценный камень - это просто другое имя для простого старого ванили vsnprintf();
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GLib Team and others 2002. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __G_PRINTFINT_H__
#define __G_PRINTFINT_H__
#ifdef HAVE_GOOD_PRINTF
#define _g_printf printf
#define _g_fprintf fprintf
#define _g_sprintf sprintf
#define _g_snprintf snprintf
#define _g_vprintf vprintf
#define _g_vfprintf vfprintf
#define _g_vsprintf vsprintf
#define _g_vsnprintf vsnprintf
#else
#include "gnulib/printf.h"
#define _g_printf _g_gnulib_printf
#define _g_fprintf _g_gnulib_fprintf
#define _g_sprintf _g_gnulib_sprintf
#define _g_snprintf _g_gnulib_snprintf
#define _g_vprintf _g_gnulib_vprintf
#define _g_vfprintf _g_gnulib_vfprintf
#define _g_vsprintf _g_gnulib_vsprintf
#define _g_vsnprintf _g_gnulib_vsnprintf
#endif
#endif /* __G_PRINTF_H__ */
Настоятельно рекомендуется снова посмотреть "Волшебника страны Оз" перед началом работы с Gnome, чтобы вы не заглядывали за кулисы. Добро пожаловать в мой кошмар!
Любой, кто думает, что Gnome более устойчив, чем C, испытывает недостаток в критическом мышлении. Вы торгуете производительностью и прозрачностью ради нескольких хороших вещей, которые лучше выполняются в STL.
Вот обновление. Похоже, разработчик понял свою ошибку:
Начиная с версии 2.46, g_mem_is_system_malloc устарела и не должна использоваться во вновь создаваемом коде.
GLib всегда использует систему malloc, поэтому эта функция всегда возвращает TRUE.
Проверяет, является ли распределитель, используемый g_malloc(), системной реализацией malloc. Если он возвращает TRUE, память, выделенная с помощью malloc (), может использоваться взаимозаменяемо с памятью, выделенной с помощью g_malloc(). Эта функция полезна для избежания дополнительной копии выделенной памяти, возвращаемой API, не основанным на GLib.
https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html