質問
どこにありますか MIN
そして MAX
C で定義されている場合、定義されているのでしょうか?
これらを一般的に実装し、可能な限り安全に入力する最善の方法は何でしょうか?(主流のコンパイラ用のコンパイラ拡張機能/ビルトインが推奨されます。)
解決
どこにありますか
MIN
そしてMAX
C で定義されている場合、定義されているのでしょうか?
そうではありません。
これらをできるだけ一般的かつ型安全に実装する最善の方法は何ですか (主流のコンパイラ用のコンパイラ拡張機能/組み込みが望ましい)。
機能として。私なら次のようなマクロは使いません #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
, 特にコードをデプロイする予定がある場合はそうです。独自に記述するか、標準のようなものを使用するか fmax
または fmin
, 、または次を使用してマクロを修正します。 GCC のタイプ (タイプセーフティのボーナスも得られます):
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
誰もが「二重評価については知っている、問題ない」と言いますが、数か月後には、最も愚かな問題を何時間もデバッグすることになるでしょう。
の使用に注意してください __typeof__
の代わりに typeof
:
ISO Cプログラムに含まれているときに機能する必要があるヘッダーファイルを書いている場合は、書き込みます
__typeof__
の代わりにtypeof
.
他のヒント
これは、sys/param.h の GNU libc (Linux) および FreeBSD バージョンでも提供されており、dreamlax によって提供される定義があります。
Debian の場合:
$ uname -sr
Linux 2.6.11
$ cat /etc/debian_version
5.0.2
$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.
FreeBSD の場合:
$ uname -sr
FreeBSD 5.5-STABLE
$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
ソース リポジトリは次のとおりです。
C ++でstd::min
とstd::max
がありますが、私の知る限りでは、相当するものはC標準ライブラリにありません。あなたが好きなマクロを自分で定義することができます。
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
しかし、この原因の問題あなたのような何かを書く場合MAX(++a, ++b)
ます。
非標準のコンパイラ拡張を回避し、純粋な標準 C (ISO 9899:2011) で完全にタイプセーフなマクロとして実装します。
解決
#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))
#define ENSURE_int(i) _Generic((i), int: (i))
#define ENSURE_float(f) _Generic((f), float: (f))
#define MAX(type, x, y) \
(type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))
使用法
MAX(int, 2, 3)
説明
マクロ MAX は、 type
パラメータ。この制御マクロは、指定された型に対して実装されている場合、両方のパラメーターが正しい型であることを確認するために使用されます。もし type
はサポートされていないため、コンパイラ エラーが発生します。
x または y のいずれかが正しい型ではない場合、コンパイラ エラーが発生します。 ENSURE_
マクロ。より多くのタイプがサポートされている場合は、そのようなマクロをさらに追加できます。算術型 (整数、浮動小数点数、ポインタなど) のみが使用され、構造体や配列などは使用されないと想定しています。
すべてのタイプが正しい場合、GENERIC_MAX マクロが呼び出されます。C マクロを作成するときの通常の標準的な予防措置として、各マクロ パラメーターを追加の括弧で囲む必要があります。
次に、C の暗黙的な型昇格に関するよくある問題があります。の ?:
演算子は、2 番目と 3 番目のオペランドのバランスをとります。たとえば、次のような結果が得られます。 GENERIC_MAX(my_char1, my_char2)
だろう int
. 。マクロがこのような潜在的に危険な型のプロモーションを実行するのを防ぐために、目的の型にキャストされた最終的な型が使用されました。
理論的根拠
マクロへの両方のパラメータを同じ型にする必要があります。それらの 1 つが異なる型である場合、マクロはタイプ セーフではなくなります。 ?:
暗黙的な型のプロモーションが行われます。そして、そうであるため、上で説明したように、最終結果を常に意図した型にキャストし直す必要もあります。
パラメータを 1 つだけ持つマクロは、もっと簡単な方法で作成できます。ただし、パラメータが 2 つ以上ある場合は、追加の型パラメータを含める必要があります。残念ながら、次のようなことは不可能であるためです。
// this won't work
#define MAX(x, y) \
_Generic((x), \
int: GENERIC_MAX(x, ENSURE_int(y)) \
float: GENERIC_MAX(x, ENSURE_float(y)) \
)
問題は、上記のマクロが次のように呼び出された場合です。 MAX(1, 2)
二人で int
, 、それでも、考えられるすべてのシナリオをマクロ展開しようとします。 _Generic
関連リスト。それで、 ENSURE_float
マクロは、関係がない場合でも展開されます。 int
. 。そして、そのマクロには意図的に float
タイプの場合、コードはコンパイルされません。
これを解決するために、マクロが誤って展開されないように、プリプロセッサ段階で ## 演算子を使用してマクロ名を作成しました。
例
#include <stdio.h>
#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))
#define ENSURE_int(i) _Generic((i), int: (i))
#define ENSURE_float(f) _Generic((f), float: (f))
#define MAX(type, x, y) \
(type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))
int main (void)
{
int ia = 1, ib = 2;
float fa = 3.0f, fb = 4.0f;
double da = 5.0, db = 6.0;
printf("%d\n", MAX(int, ia, ib)); // ok
printf("%f\n", MAX(float, fa, fb)); // ok
//printf("%d\n", MAX(int, ia, fa)); compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib)); compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db)); compiler error, one of the types is wrong
//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
return 0;
}
私は、彼らはマクロを標準化されているとは思いません。すでに浮動小数点、fmax
とfmin
(と山車のためfmaxf
、そして長いダブルス用fmaxl
)のための標準化の機能があります。
あなたは長い間あなたは副作用/二重評価の問題を認識しているようなマクロとしてそれらを実装することができます。
#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)
ほとんどの場合、あなたはそれができる最善のようにそれを行うと最適化しようとしているかを判断するために、コンパイラにそれを残すことができます。 MAX(i++, j++)
のように使用する場合、これは問題を引き起こしている間、私は一度にインクリメント値の最大値をチェック中に、これまで多くの必要性がある疑い。インクリメントまず、その後、確認します。
これはかなり最近の発展のために後半の答えです。 //gcc.gnu: - 「クリーン」ISO Cまたはtypeof
- OPは非ポータブルGCC(と打ち鳴らす)延長__typeof__
に依存している答えを受け入れているので、<のhref = "httpsの現在において入手可能なよりよい解決策があります。 ORG / onlinedocs / GCC-5.2.0 / gccの/ Typeof.html ">のgcc-4.9 のます。
#define max(x,y) ( \
{ __auto_type __x = (x); __auto_type __y = (y); \
__x > __y ? __x : __y; })
この拡張機能の明らかな利点は、各マクロ引数のみ__typeof__
ソリューションとは異なり、一度展開されていることである。
__auto_type
は、C ++ 11のauto
の限定された形です。 C ++ 11を使用した場合auto
の優れた型推論機能を使用しないダメな理由はありませんけれども、それはできない(またはべきではないのですか?)、C ++コードで使用されます。
私はのマクロがextern "C" { ... }
の範囲に含まれている場合は、この構文を使用して問題がないを想定し、言いました。例えば、Cヘッダから。私の知る限りでは、この拡張機能は、その方法の情報打ち鳴らす
私はこのバージョンを書きましたそのMSVC、GCC、C、およびC ++のための作品ます。
#if defined(__cplusplus) && !defined(__GNUC__)
# include <algorithm>
# define MIN std::min
# define MAX std::max
//# define TMIN(T, a, b) std::min<T>(a, b)
//# define TMAX(T, a, b) std::max<T>(a, b)
#else
# define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
({ \
decltype(lexpr) lvar = (lexpr); \
decltype(rexpr) rvar = (rexpr); \
lvar binoper rvar ? lvar : rvar; \
})
# define _CHOOSE_VAR2(prefix, unique) prefix##unique
# define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
# define _CHOOSE(binoper, lexpr, rexpr) \
_CHOOSE2( \
binoper, \
lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
)
# define MIN(a, b) _CHOOSE(<, a, b)
# define MAX(a, b) _CHOOSE(>, a, b)
#endif
、あなたは、三項演算子を使用しないでください。以下のリンクは、分岐せずに最小/最大機能を実現するために有用な方法を記載している。
http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMaxする
min
やmax
を定義した場合だと思うからこれは、ポインティング価値があります
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
あなたは
引数を交換する必要がfmin(-0.0,0.0)
とfmax(-0.0,0.0)
の特殊な場合のために、同じ結果を得るために
fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)
Windef.h
(ラ・#include <windows.h>
)のように見えますが、また、「二重の評価」困難に苦しむmax
とmin
(小文字)マクロを、持っているが、彼らはそうでないもののためにそこにいるには、再ロール、独自にしたいです:)
私は、男は「C」と述べた知っています...
:しかし、あなたはチャンスを持っている場合は、C ++のテンプレートを使いますtemplate<class T> T min(T a, T b) { return a < b ? a : b; }
タイプの安全、および++他のコメントで述べています。
で問題なし二つの整数のa
とb
の最大値は(int)(0.5((a+b)+abs(a-b)))
です。これはまた(double)
とダブルスのためfabs(a-b)
(フロートのための同様の)で動作することができる
関連 ブレット・ヘイルのコメント, clang
サポートを開始しました __auto_type
2016 年頃 (参照) パッチ).
最も簡単な方法は、あなたのプログラムがファイルのたくさんのモジュール化された場合、.h
ファイルにグローバル関数として定義し、いつでも好きなときにそれを呼び出すことです。そうでない場合、double MIN(a,b){return (a<b?a:b)}
は最も簡単な方法です。