web-dev-qa-db-ja.com

Cの共通配列長マクロ?

私は周りに浮かぶ配列の長さのいくつかのマクロを見てきました:

から この質問

  • #define length(array) (sizeof(array)/sizeof(*(array)))
  • #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
  • #define SIZE(array, type) (sizeof(array) / (sizeof(type))

そしてVisual Studioの _countof

#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))

私が知りたいのは:

  1. array[0]*arrayを使用しているものの違いは何ですか?
  2. なぜどちらを優先すべきですか?
  3. C++では違いますか?
32
Matt Joiner

これはより良いCバージョンです(GoogleのChromiumプロジェクトから):

_#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
_

_array[0]_を使用して_*array_または_0[array]_バージョンを改善します。これはプレーン配列の_array[0]_と同等ですが、arrayが発生するとコンパイルに失敗しますoperator[]()をオーバーロードするC++型になる。

除算は、ポインターがarrayパラメーターとして渡される多くの(すべてではない)状況でゼロ除算演算(コンパイル時に定数式であるため、コンパイル時にキャッチされる必要があります)を引き起こします。

詳細については、 配列の長さを返すCの標準関数はありますか? を参照してください。

C++コードにはより良いオプションがあります。詳細については、 マクロを使用せずにsizeof_arrayをコンパイルする を参照してください。

60
Michael Burr
  1. Array [0]と* arrayを使用する違いは何ですか?
  2. なぜどちらを優先する必要があるのですか?
  3. C++では違いますか?

(1)Cに違いはありません。C++の実際のraw配列に違いはありません。

(2)どちらか一方を好む技術的な根拠はありませんが、初心者はポインターの逆参照によって混乱する可能性があります。

(3)C++では、非常に安全でないため、通常はマクロを使用しません。実際の生の配列の代わりにポインタを渡すと、コードはコンパイルされますが、不正な結果が生じます。したがって、C++では、代わりに関数テンプレートを使用するか、または使用する必要があります。

#include <stddef.h>

typedef ptrdiff_t Size;

template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }

これは引数として実際の生の配列のみを受け入れます。

関数startOfendOfおよびcountOfのトライアドの一部であり、生の配列と標準ライブラリコンテナーの両方に適用できるように定義すると非常に便利です。私の知る限り、このトライアドはディートマーキュールによって最初に識別されました。 C++ 0xでは、startOfおよびendOfはおそらくstd::beginおよびstd::end

乾杯&hth。、

15

1)何もありません。配列の値は、その最初の要素へのポインターです。したがって、* array == array [0]
2)個人の好み
3)いいえ

このマクロは、配列がパラメーターとして関数に渡される関数内で呼び出された場合は機能しません。これは、配列オブジェクトがディープコピーではなくポインタに「減衰」を渡したためです。

3
SiegeX