タイプsize_t
の変数nの値を出力するポータブルな方法が必要です。 ANSI C89を使用しているため、z
長さ修飾子を使用できません。私の現在のアプローチは、値をlong unsigned int
にキャストすることです:
printf("%lu\n", (long unsigned int) n);
size_t
がunsigned int
またはlong unsigned int
として定義されている場合、これがどのように失敗するかはわかりません。キャストは安全ですか?
C89では、size_t
は符号なし整数型として定義されています。将来の標準とは異なり、C89は符号なし整数型のリストを次のように定義しています。
そのため、C89のsize_t
はunsigned long
より大きくなることはないため、キャストは常に安全です。これにより、未定義の動作が発生することはなく、常に完全な値を保持するのに十分な大きさになります。
注目に値する; C89標準は次のように述べています:「厳密に準拠するプログラムの動作を変更しない限り、準拠する実装に拡張機能(追加のライブラリ関数を含む)が含まれる場合があります」拡張機能を変更できないことを意味します。この動作-符号なし整数型が具体的にリストされており、したがって変更できないため、C89標準に引き続き準拠しています。
将来の標準では、これは保証ではなく、未定義の動作が発生することはありませんが、unsigned long
がsize_t
よりも小さい場合、データが失われる可能性があります。つまり、誤ったデータがユーザーに表示されます。この状況では、「安全」とラベルを付けるのをためらいます。
追加の重要な注意事項として、この回答は、C89標準に準拠しているコンパイラを指します。 C89コンパイラが上記の点で「準拠していない」可能性があります。その場合、動作をC99以降の動作と同様に扱い、未定義の動作は見られませんが、size_t
の場合はデータが失われる可能性があります。 unsigned long
よりも大きい。ただし、明確にするために、これはC89標準に準拠していません。
これを超えて、標準(1.7コンプライアンス)の私の解釈は、拡張が「厳密に準拠するプログラム」の動作を変更してはならないため、事実を変更できないと述べていますsize_t
は、準拠せずに最大でもunsigned long
でなければなりません。 そのような拡張が存在するという事実は変わりません。たとえば、GNU GCCはunsigned long long
を追加する拡張機能を提供します。私の見解では、これは非準拠ですが、実際には、そのようなことに対処する準備をする必要があります-標準はあなたがやっていることは完全に安全であると述べていますが、非準拠のコンパイラまたは拡張機能が使用されている場合、潜在的なデータ損失に備える必要があります。
このトピックに関する以前のディスカッションについては、こちらをご覧ください: https://stackoverflow.com/a/39441237/95534
size_t n = foo();
printf("%lu\n", (long unsigned int) n);
size_t
がunsigned int
またはlong unsigned int
として定義されている場合...キャストは安全ですか?
はい、キャストは安全であり、C89、C99、C11に関する未定義の動作や情報の損失はありません。
しかし、その条件が真でない場合はどうなりますか?
size_t
の範囲がunsigned long
の範囲内であると仮定することは非常に合理的です。コンパイル時テストを追加します: ref
#include <limits.h>
#if defined(__STDC__)
#if defined(__STDC_VERSION__)
#if (__STDC_VERSION__ >= 199901L)
#include <stdint.h>
#if SIZE_MAX > ULONG_MAX
#error Re-work printf size code
#endif
#endif
#endif
#endif
ポイントは、コードに依存関係があった場合-テストを追加することです。今日でも歴史的にも、すべての既知のマシンでそれが許容できるとしても、未来は未知数です。
Cは、今日、その非常に高い柔軟性でSIZE_MAX > ULONG_MAX
を許可していますが、それは確かにまれです。 IMO、SIZE_MAX > ULONG_MAX
は 淡い色の向こう側 です。
このようなテストは時々一般的ですが、可能ではありますが、super移植可能なコードを書くことは実際的ではなく、予算もかかりません。
#include <limits.h>
#if CHAR_BIT != 8 && CHAR_BIT != 16 && CHAR_BIT != 32 && CHAR_BIT != 64
#error Code depends on char size as a common power of 2.
#endif
タイプsize_tの変数nの値を出力するポータブルな方法が必要です。
しかし、OPの最上位の目標に対処するために、単純なポータブルヘルパー関数を作成できます。
// This approach works with any unsigned type
void print_size_t(size_t n) {
if (n >= 10) print_size_t(n/10);
putchar((int) (n%10) + '0');
}
再帰を避けるために、少し長い関数:
#include <limits.h>
void print_size_t(size_t n) {
char buf[sizeof n * CHAR_BIT / 3 + 2]; // 1/3 is more than log2(10)
char *p = &buf[sizeof buf - 1]; // Start at end of buf[]
*p = '\0';
do {
p--;
*p = (char) (n%10 + '0');
n /= 10;
} while (n); // Use a do {} while so print_size_t(0) prints something
fputs(p, stdout);
}