68

%hnand %hhnhまたはがポイントされたhhオブジェクトのサイズを指定する場合)を除いて、フォーマット指定子のand修飾子のポイントは何ですか?hhhprintf

可変個引数関数に適用するために標準で要求されるデフォルトのプロモーションのため、タイプcharまたはshort(またはその符号付き/符号なしのバリアント)の引数をに渡すことはできませんprintf

7.19.6.1(7)によると、h修飾子は次のとおりです。

次のd、i、o、u、x、またはX変換指定子がshortintまたはunsignedshort int引数に適用されることを指定します(引数は整数拡張に従ってプロモートされますが、その値はshortintに変換されます。または印刷前のunsignedshortint); または、次のn変換指定子が短いint引数へのポインターに適用されます。

引数が実際にタイプshortまたはunsigned shortであった場合、に昇格したint後にに変換するか、shortまたはに変換することなく、昇格unsigned shortと同じ値を生成します。したがって、タイプまたは、、、intなどの引数の場合、、、などと同じ結果が得られるはずです(タイプとの場合も同様です)。shortunsigned short%d%u%hd%hucharhh

私が知る限り、horhh修飾子が役立つ可能性がある唯一の状況は、引数がorのint範囲外で渡された場合です。shortunsigned short

printf("%hu", 0x10000);

しかし、私の理解では、このような間違った型を渡すと、とにかく未定義の動作が発生するため、0を出力することは期待できませんでした。

私が見た実際のケースの1つは、次のようなコードです。

char c = 0xf0;
printf("%hhx", c);

署名されf0たプレーンタイプの実装にもかかわらず、作成者が印刷することを期待している場合(この場合、印刷または同様のものになります)。しかし、この期待は正当化されますか?charprintf("%x", c)fffffff0

(注:元のタイプはでしたが、ではなくにcharプロモートされintて変換され、出力される値が変更されます。ただし、標準ではこの動作が指定されていますか、それとも壊れたソフトウェアが実装の詳細である可能性がありますか?頼っていますか?)unsigned charchar

4

7 に答える 7

19

考えられる理由の1つ:フォーマットされた入力関数でこれらの修飾子を使用することとの対称性のために?厳密には必要ないことは承知していますが、その価値はあったのでしょうか。

C99 Rationaleドキュメントの「h」および「hh」修飾子の対称性の重要性については言及されていませんが、委員会は、「%p」変換指定子がサポートされている理由の考慮事項として言及していますfscanf()( C99では新しいものではありませんでした-「%p」のサポートはC90にあります):

fprintfとの対称性のために、明らかに危険ですが、%pを使用した入力ポインター変換がC89に追加されました。

のセクションでfprintf()は、C99の理論的根拠のドキュメントで、「hh」が追加されたと説明されていますが、読者に次のfscanf()セクションを紹介しているだけです。

%hhおよび%llの長さ修飾子がC99で追加されました(§7.19.6.2を参照)。

私はそれが希薄なスレッドであることを知っています、しかし私はとにかく推測しているので、私はそこにあるかもしれないどんな議論でも与えるだろうと思いました。

また、完全を期すために、「h」修飾子は元のC89標準に含まれていました。おそらく、修飾子を使用するための技術的要件がなかったとしても、既存の使用が広まっているために厳密に必要でなかったとしても、そこにあるでしょう。 。

于 2011-01-03T18:21:22.880 に答える
5

モードでは%...x、すべての値が符号なしとして解釈されます。したがって、負の数は符号なし変換として出力されます。ほとんどのプロセッサが使用する2の補数演算では、符号付きの負の数と、モジュラス演算によって定義される正の符号なしの等価物との間にビットパターンに違いはありません(フィールドの最大値に1を加えたものを負の数に加算します。 C99標準に準拠)。多くのソフトウェア(特に使用する可能性が最も高いデバッグコード%x)は、符号付きの負の値とその符号なしのキャストのビット表現が同じであるという無言の仮定を行います。これは、2の補数マシンでのみ当てはまります。

このキャストのメカニズムは、値の16進表現が、異なる整数表現が異なる範囲を持つエッジ条件に達しない限り、数値が2の補数でレンダリングされたことを常に意味します(おそらく不正確です)。これは、値0がすべて0のバイナリパターンで表されない算術表現にも当てはまります。

したがって、16進数でshort表示されたネガは、プロモーションでの暗黙の符号拡張により、どのマシンでも、が埋め込まれ、印刷されます。は同じですが、フィールドのサイズに関しては視覚的に誤解を招く可能性があり、単に存在しないかなりの量の範囲を意味します。unsigned longfprintf

%hx実際のユースケースから結論付けたとおりに、このパディングを回避するために表示された表現を切り捨てます。

の動作は、の範囲外に渡されたprintf場合は未定義ですが、最も簡単な実装では、生のダウンキャストによって上位ビットが破棄されるだけなので、仕様には特定の動作は必要ありませんが、ほとんどの場合正常な実装では、切り捨てが実行されます。ただし、一般的にはそれを行うためのより良い方法があります。intshortshort

printfが値をパディングしたり、符号付きの値の符号なし表現を表示したりしない場合%hは、あまり役に立ちません。

于 2011-01-03T18:22:16.207 に答える
5

私が考えることができる唯一の用途は、unsigned shortまたはを渡し、変換指定子unsigned charを使用することです。%x単純にベアを使用することはできません。値がではなく%xに昇格する可能性があり、その場合、未定義の動作が発生します。intunsigned int

代わりに、引数をunsigned;に明示的にキャストすることもできます。または%hx/%hhxを裸の引数で使用します。

于 2011-01-04T00:17:59.727 に答える
1

et alへの可変個引数printf()は、デフォルトの変換を使用して自動的にプロモートされるため、関数に渡されるときに任意の値shortまたはchar値がプロモートされます。int

hまたは修飾子がない場合hh、正しい動作を確実に取得するには、渡された値をマスクする必要があります。修飾子を使用すると、値をマスクする必要がなくなります。実装はprintf()適切に仕事をします。

具体的には、フォーマット%hxの場合、内部のコードprintf()は次のようになります。

va_list args;
va_start(args, format);

...

int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!

私はそれshortが16ビットの量であると簡単に仮定しています。もちろん、規格は実際にそれを保証するものではありません。

于 2011-01-03T20:27:39.810 に答える
1

unsigned charsを16進数にフォーマットするときは、キャストを避けることが便利だと思いました。

        sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));

これはコーディングの利便性が低く、複数のキャスト(IMO)よりもきれいに見えます。

于 2017-12-27T17:49:10.287 に答える
1

便利なもう1つの場所は、snprintfサイズチェックです。gcc7は、snprintfを使用するときにサイズチェックを追加したため、これは失敗します

char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);

したがって、charをフォーマットするときに%dを使用する場合は、より大きなcharを使用する必要があります。

これは、%dを%hに変更したchar配列サイズを増やす代わりにそれらの修正を示すコミットです。これにより、より正確な説明も得られます

https://github.com/Mellanox/libvma/commit/b5cb1e34a04b40427d195b14763e462a0a705d23#diff-6258d0a11a435aa372068037fe161d24

于 2018-01-01T09:57:59.477 に答える
0

厳密に必要というわけではないので、Cライブラリ関数ではその理由だけではダメだということに同意します:)

さまざまなフラグの対称性にとっては「良い」かもしれませんが、「変換int」ルールを隠すため、ほとんどの場合逆効果です。

于 2011-01-03T23:13:06.027 に答える