3

実装している誰かの観点からこの質問を見てprintfください。

の引数はprintf省略記号 ( ...) を介して渡されるため、整数に昇格されます。私はそれを知っていてchar、昇進shortしないのに昇進します。同様に、対応するものについても。intintlong longunsigned

これは、varargs を読み取るときに、 にva_arg(args, int)は を使用しcharshortにはintwhileva_arg(args, long long)を使用する必要があることを意味しlong longます。

私の質問は、昇進longsize_tて昇進することです。整数の昇格に関する情報源はインターネット上にたくさんありますが、これらの型について言及しているものは見たことがありません。

PS標準への参照をいただければ幸いです。

4

3 に答える 3

2

の整数変換ランクは(6.3.1.1p1)longのランクよりも大きい必要があるため、と同じ表現(および精度)を持っている場合でも必要です。ほとんどの64ビットプラットフォームでは、64ビットであることに注意してください。Windows(LLP64プラットフォーム)は例外です。intva_arg(args, long) longintlong

size_t符号なし整数型(6.5.3.4p5、7.19p2)である必要があり、整数変換ランクがlong int(7.19p4)以下であることが推奨されます。少なくとも16ビット(7.20.3p2、最小値SIZE_MAX)の精度が必要です。(typedefからa)標準整数型である必要はありませんが、可能です。

その場合、整数変換ランクには3つの可能性がありますsize_t

  1. の精度よりも小さいintため、引数は(の精度がの精度よりも低い場合)または(2つのタイプの精度が同じ場合)のsize_tいずれかに昇格されます。いずれの場合も、書き込む必要があります(引数がにプロモートされている場合でも、同等の符号なし型の使用は7.16.1.1p2で許可されています)。intsize_tintunsigned intva_arg(args, unsigned int)size_tint
  2. と同じです。intつまりsize_t、と同じタイプunsigned intです。この場合、va_arg(args, unsigned int)またはva_arg(args, size_t)が許可されます。
  3. のそれよりも大きいですint。この場合va_arg(args, size_t)、を使用する必要があります。

size_tの精度がと同じであっても、1と3のどちらでも取得できることに注意してくださいint

これは、をsize_t使用してパラメータを抽出するva_argには、の整数変換ランクを知るか推測する必要があることを意味しますsize_t。これは、型ジェネリックマクロ(6.5.1.1)を使用して実行できます。

#define va_arg_size_t(args) _Generic((+(sizeof(0))),       \
  int:          (size_t) va_arg((args), unsigned int),     \
  unsigned int: (size_t) va_arg((args), unsigned int),     \
  default:               va_arg((args), size_t))

size_t上記のように単項プラス演算子によって昇格された場合、 ;intを抽出します。にプロモートされているunsigned int場合、またはにtypedefである場合は、 ;を抽出します。昇格せず、とは異なるタイプの場合は、ブロックにヒットします。のtypedefである場合は競合するため、オプションとしてそれ自体を提供することはできません。size_tunsigned intunsigned intunsigned intunsigned intdefaultsize_tsize_tunsigned int

これはに限定されない問題size_tptrdiff_tありwchar_t、同じ問題があることに注意してください(後者の場合、wint_t任意のwchar_t値を保持でき、昇格の対象にはなりませんが、に昇格される保証とはwchar_t 異なりwint_t、に昇格される保証はありません)。標準では、新しいタイプ、、、およびを導入する必要があることをお勧めします。同様に、のタイプについても同様です。(もちろん、上記のように使用できますが、首が痛いです。)charintspromo_tppromo_twpromo_tstdint.h_Generic

于 2012-10-12T17:16:45.090 に答える
2

Cは言います(私のものを強調してください):

(C99, 6.3.1.1p2) " int または unsigned int を使用できる式では、次を使用できます。

— 整数変換ランクが int および unsigned int のランク以下である整数型のオブジェクトまたは式。

— _Bool、int、signed int、または unsigned int 型のビットフィールド。

int が元の型のすべての値を表すことができる場合、値は int に変換されます。それ以外の場合は、unsigned int に変換されます。これらは、整数昇格と呼ばれます。48)他のすべての型は、整数昇格によって変更されません。"

于 2012-10-12T16:13:11.867 に答える
1

型の引数はlong昇格されません。に関連する整数プロモーションsize_tは、次のように要約できます。

  1. size_tが の範囲内にある場合int、 に昇格int
  2. size_tが の範囲内にある場合unsigned int、 に昇格unsigned int
  3. それ以外の場合は、size_tより高いコンバージョン ランク (したがって幅) をunsigned int持ち、プロモーションは発生しません。

自明なケースは、size_tが のエイリアスであるか、 より大きな幅を持っている場合ですunsigned int。これらの場合、プロモーションは発生せずsize_t、可変引数を読み取るために使用できます。

エッジケースは

  • size_tの範囲内ですint
  • size_tは の範囲内ではありませんが、実際にintは ではなく の範囲内ですunsigned intunsigned int

後者は、 が と同じ幅の拡張整数型であるint場合のパディングを含む場合に発生する可能性があります。size_tunsigned int

整数表現にパディング ビットが含まれていないunsigned intと仮定すると、未定義の動作である可能性があるにもかかわらず、C 言語のすべての合理的な実装で機能する可変引数を読み取ることで、両方のエッジ ケースをカバーできます。

于 2012-10-12T16:51:37.443 に答える