32

あなたの意見では、どの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);
...
4

18 に答える 18

36
#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)

そしてもちろん、各種MIN、MAX、ABSなど。

ところで、上記のいずれも C の関数では実装できないことに注意してください。

PS私はおそらく、上記のIMPLIESマクロを最も有用なものの1つとして選び出すでしょう. その主な目的は、次のように、よりエレガントで読みやすいアサーションの記述を容易にすることです。

void foo(int array[], int n) {
  assert(IMPLIES(n > 0, array != NULL));
  ...
于 2009-11-20T18:11:17.480 に答える
23

C マクロの重要なポイントは、適切に使用することです。私の考えでは、3つのカテゴリがあります(定数にわかりやすい名前を付けるためだけにそれらを使用することは考慮していません)

  1. 繰り返したくないコードの省略形として
  2. 汎用機能の提供
  3. C言語の構造を変更する(らしい)

最初のケースでは、マクロはプログラム内 (通常はファイルのみ) に存在するため、投稿したようなマクロを使用できますが、パラメーターと使用の二重評価から保護されていません{...};(危険な可能性があります!)。

2 番目のケース (さらに 3 番目のケース) では、マクロが実際の C 構造体であるかのように正しく動作するように細心の注意を払う必要があります。

GCC から投稿したマクロ (min と max) はこの例です。グローバル変数を使用し、_a_b重評価のリスクを回避します (のようにmax(x++,y++)) (まあ、GCC 拡張機能を使用しますが、概念は同じです)。

物事をより明確にするのに役立つマクロを使用するのが好きですが、それらは鋭いツールです! おそらくそれが彼らの評判が悪くなった理由です。私は、それらは非常に便利なツールであり、それらが存在しなければ 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 のフレーバーを得ることができます。

この例を好まない人もいるかもしれませんが、単純なマクロがコードをより読みやすく、表現力豊かにする方法を示すのに最適だと思います。

于 2009-11-20T18:14:50.527 に答える
18

C99 の for-each ループ:

#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);
}
于 2009-11-20T20:22:23.717 に答える
11

異なるコンテキストでデータを複数回定義する必要がある場合、マクロを使用すると、同じものを何度も再リストする必要がなくなります。

たとえば、すべての色を 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]);
};
于 2010-07-24T22:07:10.387 に答える
7
#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は意図的なものであることに注意してください。ソースの場所を前に付けてフォーマットされた文字列を出力します。私はリアルタイムの組み込みシステムで作業しているため、出力にタイムスタンプも含めることがよくあります。

于 2010-07-24T19:27:53.277 に答える
6

GCC、特に GNU 拡張を使用した C99 の foreach ループ。文字列と配列で動作します。動的に割り当てられた配列は、それらを配列へのポインターにキャストし、逆参照することで使用できます。

#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);
}
于 2010-07-24T18:56:42.377 に答える
6

他の誰かがcontainer_of()について言及しましたが、この本当に便利なマクロについての説明はありませんでした。次のような構造体があるとします。

struct thing {
    int a;
    int b;
};

bへのポインターがある場合、 container_of()を使用して、型安全な方法でへのポインターを取得できます。

int *bp = ...;
struct thing *t = container_of(bp, struct thing, b);

これは、抽象的なデータ構造を作成するのに役立ちます。たとえば、queue.h が SLIST のようなもの (操作ごとに大量のクレイジーなマクロを作成する) を作成するために採用するアプローチを採用するのではなく、次のような 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 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);
于 2010-07-24T21:55:34.303 に答える
5
#define COLUMNS(S,E) [ (E) - (S) + 1 ]


struct 
{
    char firstName COLUMNS ( 1, 20);
    char LastName  COLUMNS (21, 40);
    char ssn       COLUMNS (41, 49);
}

エラーが発生しやすいカウントを節約できます

于 2009-11-20T18:45:50.340 に答える
4

これは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
于 2009-11-20T20:05:59.350 に答える
2

私もこれが好きです:

#define COMPARE_FLOATS(a,b,epsilon) (fabs(a - b) <= epsilon * fabs(a))

では、マクロ嫌いのあなたはどのように浮動小数点比較を公平に行っているのでしょうか?

于 2009-11-20T17:56:40.660 に答える
2
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))

x より大きい最も近い 32 ビット符号なし整数を見つけます。これを使用して、配列のサイズを 2 倍にします (つまり、最高水準点)。

于 2009-11-21T03:44:41.917 に答える
2

標準的なものだけ:

#define LENGTH(array) (sizeof(array) / sizeof (array[0]))
#define QUOTE(name) #name
#define STR(name) QUOTE(name)

しかし、そこにはあまりにもスパイシーなものはありません。

于 2009-11-20T18:08:28.467 に答える
1

バイト、単語、dword を word、dword、qword にパックします。

#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) 

引数を括弧で囲むことは、展開の副作用を避けるために常に良い習慣です。

于 2009-11-21T07:22:29.417 に答える
0

そのようなマルチタイプの最小値と最大値も

//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; })
于 2009-11-20T17:40:54.123 に答える
0

私が定期的に使用する (非常に少ないものの 1 つ) は、引数または変数を未使用として宣言するマクロです。これに注意するための最も互換性のあるソリューション(IMHO)は、コンパイラによって異なります。

于 2009-11-20T21:25:02.530 に答える
0

浮動小数点xが数値でないかどうかを確認する:

#define ISNAN(x) ((x) != (x))
于 2009-11-20T18:07:50.530 に答える
-1

TRUEとFALSEが人気があるようです。

于 2009-11-20T19:01:59.073 に答える
-1

これは素晴らしいです:

#define NEW(type, n) ( (type *) malloc(1 + (n) * sizeof(type)) )

そして、私はそれを次のように使用します:

object = NEW(object_type, 1);
于 2009-11-20T17:51:38.657 に答える