なぜここでマクロを使用するのかは分かりません。コードの重複を避けたいですか?あるいは、ソートルーチンの型を独立させたいと思っていますか?
とにかく、あなたのマクロは、いくつかの誤りがあります。
- あなたはおそらく、あなたは括弧でマクロの引数を守る必要があることを読みました。マクロはテキストの置き換えであるため、通常は良いアドバイスです。例えば、悪名高い
SQ(x + 1)
はx + 1*x + 1
に解決されます。あなたの場合、アドバイスは間違っています。コード内に構文的に間違った "演算子"、例えば(-)
と(<)
があります。ちょうどsign
とoper
を使用してください。
- でも、
sign sign
は- -
または+ +
に解決されますが、これはあなたが望むものではありません。 i++
を等しく有効なi = i + 1
に書き換えるか、トークンペースト演算子sign##sign
を使用して、--
または++
を生成することができます。
- マクロは機能ではありません。おそらく関数内でマクロを呼び出すつもりです。スコープ内にあるマクロを呼び出すすべてのローカル変数もマクロのスコープ内にあります。つまり、おそらくこれらのポインタをすべて定義する必要はありません。
- なぜ配列要素タイプ
var_t
を渡しますか?私は、SetVector
とGetVector
はマクロではないので、型の独立性はフラットになると思います。
var_t
が配列要素の型である場合、インデックスは必ずしも同じ型である必要はありません。それは整数型でなければなりません。 (あなたの要素は<
演算子と同等でなければならないので、これは算術型の1つですが、char
の配列が256要素より長い場合どうなりますか?
- 要素が算術型の場合は、おそらく
GetValue
とSetValue
の呼び出しは必要ありません。 =
演算子を使用して値を割り当てることができます。
これはあなたがしていることを本当にわからないと思います。それに加えて、マクロの既知の落とし穴や欠点があります。ここではマクロを使用しませんここに。コメントで
補遺 、POは、マクロは二つのことを達成すべきであると述べている:それは繰り返しのコードを避ける必要があり、それは配列の要素の種類のソートを独立させる必要があります。これらは2つの異なるものです。
コードの繰り返しを避けるための短いローカルマクロを書くことは、特にコードが変数をいくつかの場所で同期させておく必要がある場合に便利です。あなたの状況でそれは役に立ちますか?
だから、あなたはあなたの上向き、バブリングコード持っている:
int done = 0;
while (!done) {
done = 1;
for (int i = 1; i < n; i++) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
}
を(これは、2つの配列要素を交換するswap
機能を使用して、それが/取得し使用していないので、それはあなたのバージョンよりも簡単です。 。これら二つのスニペットはループ制御のみが異なる
while (!done) {
done = 1;
for (int i = n - 1; i > 0; i--) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
}
:セットアクセサ関数は)今、あなたは下向きバブリングの対応を記述します。両方とも1からn - 1
までのすべての指標にアクセスします。したがって、マクロは開始値と終了値を渡す必要があります。しかし、比較が–より小さいかより大きく、どちらの方法が–よりも大きく、インデックスを増分するか減らすかを知る必要があります。それは単純なループのための4つのデータです。
あなたは比較を取り除き、両方向に!=
を使用することができます。しかし配列が空の場合、ループは失敗します。
インデックスとして符号なし整数を使用すると、空の配列で上記の後方ループが既に失敗します。順方向および逆方向のlopsは非対称であり、下限および上限は非対称であるため、下限は常にインクルーシブ、上限は常に排他的です。このフォワードループ:ここ
for (unsigned int i = n; i-- > 0;) ...
は、デクリメントが条件で発生し、更新部分が空である:
for (unsigned int i = 0; i < n; i++) ...
は、以下の下位相当しています。利点はまったく同じ境界、0
とn
をそのまま使用しますが、ループ本体に入る前にデクリメントして、同じ有効範囲の数字、0
〜n - 1
にアクセスすることです。そして、それは変数をループするための自然な選択肢であるunsigned intで動作します。
短いストーリーを短くする:前方および後方のループはCでは非対称なので、それらのマクロを書くのは容易ではありません。構文のCはfor i = 1 to n
よりも冗長ですが、それはそうです。適切なインデックス名を選択することでそれを受け入れ、入力痛みを緩和します。i
ではなくcurrent_index
です。
マクロを使用せずにコードを少なくすることはできますか?もちろん:今、あなたの実際のソート機能は次のようになり(これらの関数は、現在のコンパイル単位にプライベートstatic
、すなわちです。)
static int bubble_up(int a[], int n)
{
int done = 1;
for (int i = 1; i < n; i++) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
return done;
}
static int bubble_down(int a[], int n)
{
int done = 1;
for (int i = n; i-- > 1;) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
return done;
}
:
void sort_bubble_up(int a[], int n)
{
int done = 0;
while (!done) {
done = bubble_down(a, n);
}
}
void sort_bubble_down(int a[], int n)
{
int done = 0;
while (!done) {
done = bubble_down(a, n);
}
}
void sort_shaker(int a[], int n)
{
int done = 0;
while (!done) {
done = bubble_up(a, n) || bubble_down(a, n);
}
}
あなたは一度上下に泡立てるとのための2つの関数を書くことができます
あなたは空のループ本体を恐れていない場合は、あなたもそれらを降りることができます。
void sort_bubble_up(int a[], int n)
{
while (bubble_down(a, n)) { }
}
void sort_bubble_down(int a[], int n)
{
while (bubble_down(a, n)) { }
}
void sort_shaker(int a[], int n)
{
while (bubble_up(a, n) || bubble_down(a, n)) { }
}
すべてこのコードは唯一int
のために働きますしかし、型の独立性に近づく標準ライブラリの方法は、void *
ポインタとユーザー定義比較関数を介してバイトレベルで作業することです。ソート機能qsort
は、これを実行します。
C++やその他の言語には、いくつかの種類のアルゴリズムを記述できるテンプレートがあります。テンプレートを "インスタンス化"すると、コンパイラはこのタイプの関数を作成し、それを呼び出します。
これはマクロでエミュレートできます。
#define BUBBLE_SORT(ARRAY, N, TYPE) do { \
int done = 0; \
int i; \
\
while (!done) { \
done = 1; \
\
for (i = 1; i < N; i++) { \
if (ARRAY[i - 1] > ARRAY[i]) { \
TYPE sawp = ARRAY[i]; \
\
ARRAY[i] = ARRAY[i - 1]; \
ARRAY[i - 1] = swap; \
done = 0; \
} \
} \
} \
} while (0)
をして、そのようなマクロを使用します:あなただけの関数本体でマクロを呼び出したい場合は、定義することができ
char c[] = "Mississippi";
BUBBLE_SORT(c, strlen(c), char);
(thzeマクロの周りdo { ... } while (0)
事はマクロ振る舞いをすることループボディの新しいスコープでローカル変数が可能です。)
このような複数行のマクロは、デバッグが難しいという問題があります。本文にエラーがある場合は、エラーメッセージでマクロが呼び出された行の番号を取得するだけです。 (しかし、あなたは、プリプロセッサマクロことをどのように解決するか確認するために、ほとんどのコンパイラで-E
を使用することができます。)
結論:
- をマクロは便利ですが、あなたは何をしているかを知っている必要があります。一般的には、デバッグが難しく、しばしば他の人には理解しにくいため、避けるようにしてください。 (そして、この他の人が半年後になるかもしれません。)
- マクロを使用する必要がある場合は、可能な限り自然に見えるようにしてください。
>
または+
のような合格者は注意が必要です。
- 共通コードにはマクロではなく関数を使用します。
- Cはさまざまなタイプの処理方法をサポートしています。
qsort
がバブルソートの実装のためにマクロを使うよりも、どのように機能するかを知ることは、(あまり楽しいものではない)もっと便利です。
- あなたは本当に種類に依存しない多くのコードを記述する必要がある場合は、おそらく誤りである何C.
を使うべきではないのですか? – leyanpan
マクロとして長いコードを開発するのは悪いことです。あなたの考え方はC++のテンプレートで非常に良い見通しを持っています –
ここでマクロを使用するのは何ですか?上向き/下向きのバブルソートとシェイクソートを実装する際に、冗長なコードを置き換えたいだけですか? 'Get' /' SetValue'が型に依存しないように見える場合の型は何ですか?そしてあなたのマクロをどのように呼び出すのですか? –