CおよびGTK +でプログラミングしているときに、g_strdup_printf
、g_free
、g_strcmp0
などおよび他のGLib関数を使用する方が「良い」のはなぜですか?
一般に、GLibの目的はユーティリティと移植性のライブラリです。それら自体がそれを使用することを検討する理由です。
あなたが言及する特定の関数はすべて、C標準ライブラリのバリアントに加えて何か特別なものを提供します。
g_strdup_printf
はsprintf
に似ていますが、実際にはバッファーを割り当てて、バッファーの大きさの推測を省きます。 (戻り値はg_free
'dである必要があります。)g_free
はfree
に似ていますが、NULLポインターをチェックします。g_strcmp0
はstrcmp
に似ていますが、NULLポインターを空の文字列のように扱い、それを前にソートします。複数のオペレーティングシステムで一貫した動作をするため。それは移植性の問題です。
Linux以外のUNIX環境、またはプログラムがWindowsでコンパイルされている場合、これらの関数の一部は、ターゲットオペレーティングシステム上で存在しないか、動作が異なる場合があります。
Glibバージョンを使用すると、一貫した動作が保証されます。
それらの動作は、GTK +がサポートするすべてのプラットフォームで明確に定義されていますが、ネイティブ関数はおそらく途中で動作する可能性があります。
これはよく意図されていますが、うまく実行されていません。ポインタを2回以上free()しようとしても、プログラムがクラッシュしたり燃えたりしないのは、ちょっといいことです。または、NULL文字列を並べ替えます。しかし、それは混合された祝福です。これにより、コード内のこれらの厄介なバグを発見することもできなくなります。非標準の関数に依存しているため、いつかプログラムを移植するのに苦労するだけでなく、コードにバグがあり、見つからなかったために本当に苦労するでしょう。でる。
GLibは、コレクションタイプ(リンクリスト、配列、ハッシュテーブルなど)など、今日のプログラミング言語に期待される移植性と基本的な機能を提供します。 GLibが提供できるメリットのいくつかを次に示します。
移植性
GLibのポイントは、C標準ではなく、標準の実装に移植できることです。 GLibは、これらの厄介なバグがあるプラットフォームにコードを移植する必要があるまで、一見役に立たないように見える可能性のある既知の癖を処理します。
多くの人が批判しているように、_g_free
_の例を見てみましょう。 C99が動作するはずだと言っていても、free(NULL)
が失敗するプラットフォームがあります 。そのチェックは少なくとも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ライブラリには罠がたくさんあり、作成するコードのすべての行を細かく管理する必要がないので安心です。一部の関数のマンページの[〜#〜]バグ[〜#〜]セクションを読むだけでわかります。エラーをチェックする定型コードが少ないほど、コードが読みやすくなり、保守性が向上し、バグが少なくなります。
機能
もう1つのポイントは、GLibが提供する多数のコレクションタイプであり、再実装する必要がないことです。リンクリストの再実装が簡単だからといって、それを実行する必要があるとは限りません。一部の開発者はNot Invented Here症候群を患っており、独自に再開発するため、いくつかのリンクリスト実装を含むコードを出荷した別の会社で働いていました。 GLibのような一般的な、徹底的にテストされた、広く普及しているライブラリは、このナンセンスを回避するのに役立ちます。非常に具体的なパフォーマンスの制約がない限り、そのようなものを再開発しないでください。
10年前は、Gnome libを使用することは理にかなっているかもしれませんが、今ではレガシーの責任です。 C89は間違いなく世界で最も標準的な言語であり、非常に安定した機能と構文を備えているため、他の人のC89コードをデバッグすることは可能です。
対照的に、Gnomeのglibは、C標準の外部で関数の機能を変更するため、Cで作成されたあいまいなラッパーコードのデバッグに対処できるだけでなく、Gnomeがラッパー関数を変更するためにコードが機能しなくなる可能性があります。
別紙A:g_snprintf()
標準のsprintf()関数のより安全な形式。出力はn文字(終了ヌル文字を含む)を超えないことが保証されているため、バッファオーバーフローが発生しないことを簡単に確認できます。
G_strdup_printf()も参照してください。
1.2.3より前のバージョンのGLibでは、出力が切り捨てられた場合、この関数は-1を返す場合があり、切り捨てられた文字列はヌル終了されない場合があります。 1.3.12より前のバージョンでは、この関数は出力文字列の長さを返します。
G_snprintf()の戻り値は、ISO C99で標準化されているsnprintf()関数に準拠しています。これは、出力文字列の長さを返す従来のsnprintf()とは異なることに注意してください。
Format Stringには、Single UnixSpecificationで指定されている位置パラメータを含めることができます。
Gnomeの代わりに(さらに別の)リンクリストを作成し、さらに別のバージョンのsnprintf()と、メモリをサイレントにmalloc()する一連のくだらないラッパーコードを記述して、1つの絶対的な最大値を壊すことに興奮しているわけではありません。 Cコーディングの例:"常に同じスコープ内のmalloc()とfree()" g_strdup_printf()を置き換えます。
g_strdup_printf()
標準のCsprintf()関数に似ていますが、必要な最大スペースを計算し、結果を保持するためにメモリを割り当てるため、より安全です。返された文字列は、不要になったときにg_free()で解放する必要があります。
これに加えて、コード内で大量の文字列を変更して、gcharをcharに、gintをintに、gbooleanをboolに、などの「便利な」ことを行うスリルを加えて、Subversionの比較が今や電話帳。さらに悪いことに、このようなものは.hファイル全体に散らばっているため、コードをますます変更する必要があります。そのため、ボートの死体のように、巨大な混乱に拡大し続けます。
契約ジョブをスコープしていて、glib.hどこかを参照している場合は、実行してください!!! NOと言ってください!。
PS:ソースをダウンロードし、Gnome固有のタイプをすべて削除し、それを再コンパイルして独自の「g _」を作成します。機能が少なく、機能し、時間の大幅な節約になります。
図表B:g_strdup_printf()
Gnomeのもっと恐ろしいGnomeクラッポラ。 Gnomeにはg_strdup_vprintf()のような「素敵な」関数がたくさんあり、返された文字列を保持するために必要なストレージの量を「魔法のように」知っています。私は「魔法」の裏側を見る機会がありました。これは、これまでで最も恐ろしいCの乱用に対して私の賞を受賞します。
すべてのラッパー関数を介してg_strdup_vprintf()をトレースし続けると、gmessages.c ...でこのgemに到達します。
/**
* 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が追加されるので、もちろん恐ろしい費用で、保証されたヌルターミネーターの余地がありますが、彼らはあなたを賭けているコードの奥深くにそれを隠しています」ただあきらめて盲目的にそれを使用し、これがどんなに大規模な脳のおならであるかに気づかないでしょう。やあ、みんなありがとう。私は自分のコードをクロールするのが大好きです。
_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を使用する前に、Wizard Of Ozをもう一度見ることを強くお勧めします。そうすれば、カーテンの後ろを見ないようにすることができます。私の悪夢へようこそ!
GnomeがCよりも安定していると考える人は誰でも、批判的思考にひどく欠けています。パフォーマンスと透明性を、STLでより適切に実行されるいくつかの優れたものと交換します。