最も有用なユーザー製のCマクロ(GCC、C99)? [閉まっている
-
21-09-2019 - |
質問
何 c マクロはあなたの意見で最も有用ですか?次のものを見つけました。 c:
#define v3_op_v3(x, op, y, z) {z[0]=x[0] op y[0]; \
z[1]=x[1] op y[1]; \
z[2]=x[2] op y[2];}
それはそのように機能します:
v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...
解決
C99でのリーチループ:
#define foreach(item, array) \
for(int keep=1, \
count=0,\
size=sizeof (array)/sizeof *(array); \
keep && count != size; \
keep = !keep, count++) \
for(item = (array)+count; keep; keep = !keep)
int main() {
int a[] = { 1, 2, 3 };
int sum = 0;
foreach(int const* c, a)
sum += *c;
printf("sum = %d\n", sum);
// multi-dim array
int a1[][2] = { { 1, 2 }, { 3, 4 } };
foreach(int (*c1)[2], a1)
foreach(int *c2, *c1)
printf("c2 = %d\n", *c2);
}
他のヒント
#define IMPLIES(x, y) (!(x) || (y))
#define COMPARE(x, y) (((x) > (y)) - ((x) < (y)))
#define SIGN(x) COMPARE(x, 0)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
#define SWAP(x, y, T) do { T tmp = (x); (x) = (y); (y) = tmp; } while(0)
#define SORT2(a, b, T) do { if ((a) > (b)) SWAP((a), (b), T); } while (0)
#define SET(d, n, v) do{ size_t i_, n_; for (n_ = (n), i_ = 0; n_ > 0; --n_, ++i_) (d)[i_] = (v); } while(0)
#define ZERO(d, n) SET(d, n, 0)
そして、もちろん、さまざまな分、最大、ABなど。
ところで、Cの関数によって上記のいずれも実装できないことに注意してください。
PS私はおそらく上記を選ぶでしょう IMPLIES
最も有用なものの1つとしてマクロ。その主な目的は、よりエレガントで読みやすいアサーションの執筆を促進することです。
void foo(int array[], int n) {
assert(IMPLIES(n > 0, array != NULL));
...
Cマクロを使用した重要なポイントは、それらを適切に使用することです。私の考えには、3つのカテゴリがあります(定数に記述名を与えるためだけにそれらを使用することを考慮していません)
- コードの速記として、繰り返したくない
- 一般的な使用機能を提供します
- C言語の構造を変更する(明らかに)
最初のケースでは、マクロはプログラム(通常はファイルのみ)の中に住んでいるため、パラメーターと用途の二重評価から保護されていない投稿のようなマクロを使用できます。 {...};
(潜在的に危険です!)。
2番目のケース(およびさらに3番目の場合)では 非常に マクロが実際のCコンストラクトであるかのように正しく動作するように注意してください。
GCC(MINとMAX)から投稿したマクロはこの例です。彼らはグローバル変数を使用しています _a
と _b
二重評価のリスクを回避するために(のように max(x++,y++)
)(まあ、彼らはGCC拡張機能を使用しますが、コンセプトは同じです)。
私はマクロを使用するのが好きです。そこでは物事をより明確にするのに役立ちますが、それらは鋭いツールです!おそらくそれが彼らにそのような悪い評判を与えたものであり、私は彼らが非常に有用なツールであり、Cが存在しなければCがはるかに劣っていただろうと思います。
他の人がポイント2(関数としてのマクロ)の例を提供しているのを見て、新しいCコンストラクトを作成する例を示しましょう:有限状態マシン。 (私はすでにこれをSOに投稿しましたが、私はそれを見つけることができないようです)
#define FSM for(;;)
#define STATE(x) x##_s
#define NEXTSTATE(x) goto x##_s
この方法で使用すること:
FSM {
STATE(s1):
... do stuff ...
NEXTSTATE(s2);
STATE(s2):
... do stuff ...
if (k<0) NEXTSTATE(s2);
/* fallthrough as the switch() cases */
STATE(s3):
... final stuff ...
break; /* Exit from the FSM */
}
このテーマにバリエーションを追加して、必要なFSMのフレーバーを取得できます。
誰かがこの例を気に入らないかもしれませんが、私はあなたのコードをより単純なマクロをより読みやすく表現力豊かにすることがどれほど簡単であるかを示すのに最適だと思います。
さまざまなコンテキストでデータを複数回定義する必要がある場合、マクロは同じことを複数回再リストする必要があることを避けるのに役立ちます。
たとえば、すべての色を2回リストするのではなく、色の酵素と列から弦への関数を定義すると、色のファイルを作成できます(colors.def):
c(red)
c(blue)
c(green)
c(yellow)
c(brown)
これで、cファイルで列挙と文字列変換関数を定義できます。
enum {
#define c(color) color,
# include "colors.def"
#undef c
};
const char *
color_to_string(enum color col)
{
static const char *colors[] = {
#define c(color) #color,
# include "colors.def"
#undef c
};
return (colors[col]);
};
#if defined NDEBUG
#define TRACE( format, ... )
#else
#define TRACE( format, ... ) printf( "%s::%s(%d)" format, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__ )
#endif
間のコンマがないことに注意してください "%s::%s(%d)"
と format
意図的です。ソースの場所が準備されたフォーマットされた文字列を印刷します。私はリアルタイムの組み込みシステムで作業しているので、頻繁に出力にタイムスタンプも含めます。
GCCのためのforeachループ、特にGNU拡張機能を備えたC99。文字列と配列で動作します。動的に割り当てられた配列は、配列へのポインターにそれらをキャストしてから、それらを避難させることで使用できます。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define FOREACH_COMP(INDEX, ARRAY, ARRAY_TYPE, SIZE) \
__extension__ \
({ \
bool ret = 0; \
if (__builtin_types_compatible_p (const char*, ARRAY_TYPE)) \
ret = INDEX < strlen ((const char*)ARRAY); \
else \
ret = INDEX < SIZE; \
ret; \
})
#define FOREACH_ELEM(INDEX, ARRAY, TYPE) \
__extension__ \
({ \
TYPE *tmp_array_ = ARRAY; \
&tmp_array_[INDEX]; \
})
#define FOREACH(VAR, ARRAY) \
for (void *array_ = (void*)(ARRAY); array_; array_ = 0) \
for (size_t i_ = 0; i_ && array_ && FOREACH_COMP (i_, array_, \
__typeof__ (ARRAY), \
sizeof (ARRAY) / sizeof ((ARRAY)[0])); \
i_++) \
for (bool b_ = 1; b_; (b_) ? array_ = 0 : 0, b_ = 0) \
for (VAR = FOREACH_ELEM (i_, array_, __typeof__ ((ARRAY)[0])); b_; b_ = 0)
/* example's */
int
main (int argc, char **argv)
{
int array[10];
/* initialize the array */
int i = 0;
FOREACH (int *x, array)
{
*x = i;
++i;
}
char *str = "hello, world!";
FOREACH (char *c, str)
printf ("%c\n", *c);
/* Use a cast for dynamically allocated arrays */
int *dynamic = malloc (sizeof (int) * 10);
for (int i = 0; i < 10; i++)
dynamic[i] = i;
FOREACH (int *i, *(int(*)[10])(dynamic))
printf ("%d\n", *i);
return EXIT_SUCCESS;
}
このコードは、GNU/LinuxでGCC、ICC、およびClangで動作するようにテストされています。
ラムダ式(GCCのみ)
#define lambda(return_type, ...) \
__extension__ \
({ \
return_type __fn__ __VA_ARGS__ \
__fn__; \
})
int
main (int argc, char **argv)
{
int (*max) (int, int) =
lambda (int, (int x, int y) { return x > y ? x : y; });
return max (1, 2);
}
#define COLUMNS(S,E) [ (E) - (S) + 1 ]
struct
{
char firstName COLUMNS ( 1, 20);
char LastName COLUMNS (21, 40);
char ssn COLUMNS (41, 49);
}
いくつかのエラーが発生しやすいカウントを保存してください
他の誰かが言及した container_of(), 、しかし、この本当に便利なマクロについて説明しませんでした。このように見える構造体があるとしましょう。
struct thing {
int a;
int b;
};
ポインターがある場合 b, 、使用できます container_of() ポインターを取得します もの 安全な方法で:
int *bp = ...;
struct thing *t = container_of(bp, struct thing, b);
これは、抽象的なデータ構造を作成するのに役立ちます。たとえば、slist(すべての操作のためのクレイジーなマクロのトン)のようなものを作成するためにかかるアプローチqueue.hを取るのではなく、次のようなslist実装を書くことができます。
struct slist_el {
struct slist_el *next;
};
struct slist_head {
struct slist_el *first;
};
void
slist_insert_head(struct slist_head *head, struct slist_el *el)
{
el->next = head->first;
head->first = el;
}
struct slist_el
slist_pop_head(struct slist_head *head)
{
struct slist_el *el;
if (head->first == NULL)
return NULL;
el = head->first;
head->first = el->next;
return (el);
}
クレイジーなマクロコードではありません。エラーで優れたコンパイラライン数を提供し、デバッガーでうまく機能します。また、構造体が複数のタイプを使用する場合を除いて、それはかなりタイプセーフです(例:許可されている場合 struct color 以下の例では、より多くのリンクされたリストに載っています。 色 1)。
ユーザーはこのようにライブラリを使用できるようになりました。
struct colors {
int r;
int g;
int b;
struct slist_el colors;
};
struct *color = malloc(sizeof(struct person));
color->r = 255;
color->g = 0;
color->b = 0;
slist_insert_head(color_stack, &color->colors);
...
el = slist_pop_head(color_stack);
color = el == NULL ? NULL : container_of(el, struct color, colors);
これはLinuxカーネル(GCC固有)からのものです。
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); })
他の回答から別の欠落:
#define LSB(x) ((x) ^ ((x) - 1) & (x)) // least significant bit
私もこれが好きです:
#define COMPARE_FLOATS(a,b,epsilon) (fabs(a - b) <= epsilon * fabs(a))
そして、マクロヘイターはどのようにして公正な浮動小数点比較を行いますか?
標準的なものだけ:
#define LENGTH(array) (sizeof(array) / sizeof (array[0]))
#define QUOTE(name) #name
#define STR(name) QUOTE(name)
しかし、そこにはあまりにも鋭いものはありません。
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
xよりも大きい最も近い32ビットの符号なし整数を見つけます。これを使用して、配列のサイズを2倍にします(つまり、高水マーク)。
バイト、単語、dwordsを単語、dwords、qwordsに詰め込む:
#define ULONGLONG unsigned __int64
#define MAKEWORD(h,l) ((unsigned short) ((h) << 8)) | (l)
#define MAKEDWORD(h,l) ((DWORD) ((h) << 16)) | (l)
#define MAKEQWORD(h,l) ((ULONGLONG)((h) << 32)) | (l)
括弧を描く議論は、拡張に対する副作用を回避することは常に良い習慣です。
また、マルチタイプの最小値とそのような最大値
//NOTE: GCC extension !
#define max(a,b) ({typeof (a) _a=(a); typeof (b) _b=(b); _a > _b ? _a:_b; })
#define min(a,b) ({typeof (a) _a=(a); typeof (b) _b=(b); _a < _b ? _a:_b; })
フローティングポイントかどうかを確認します バツ 数ではありません:
#define ISNAN(x) ((x) != (x))
私が定期的に使用する(非常に少数の)1つは、引数または変数を未使用と宣言するマクロです。これに注意する最も互換性のあるソリューション(IMHO)は、コンパイラによって異なります。
これは素晴らしいです:
#define NEW(type, n) ( (type *) malloc(1 + (n) * sizeof(type)) )
そして、私はそれを次のように使用します:
object = NEW(object_type, 1);
真と偽は人気があるようです。