19

私のコードを見てください:

#include <stdint.h>

int main(int argc, char *argv[])
{
unsigned char s = 0xffU;
char ch = 0xff;
int val = 78;
((int8_t) + (78)); /*what does this mean*/

INT8_C(val);    /*equivalent to above*/

signed char + 78; /*not allowed*/

return 0;
}

のマクロ定義<stdint.h>は次のとおりです。

#define INT8_C(val) ((int8_t) + (val))

このプラス記号の意味または重要性は何ですか?

4

4 に答える 4

26

スニペット:

((int8_t) + (78));

value を取り、unaryを適用し、それを型にキャストしてから捨てる式です法的な表現とまったく違いはありません。78+int8_t

42;
a + 1;

また、式を評価して結果を破棄します (ただし、コンパイラが副作用がないと判断できる場合、これらは最適化されて存在しない可能性があります)。

これらの「裸の」式は C で完全に有効であり、一般に with などの副作用がある場合にのみ役立ちます。これは、値をインクリメントするという副作用i++で計算して破棄します。i

そのマクロを使用する必要がある方法は、次の行に沿ったものです。

int8_t varname = INT8_C (somevalue);

一見冗長な単項演算子の理由は+、標準で見つけることができます。C99 の引用6.5.3.3 Unary arithmetic operators /1:

単項 + または - 演算子のオペランドは算術型でなければなりません。

そして、で6.2.5 Types, /18

整数型と浮動小数点型をまとめて算術型と呼びます。

つまり、単項+は、ポインタ、複素数、または構造体など、マクロ内の他のすべてのデータ型を使用することを防ぎます。

そして最後に、あなたの理由:

signed char + 78;

スニペットが機能しないのは、同じではないためです。これは型の変数を宣言し始めていますが、それは正当な変数名ではないため、signed charに到達するとチョークします。+作業スニペットと同等にするには、次を使用します。

(signed char) + 78;

+78type への値のキャストですsigned char

また、 C99 に従って7.8.14 Macros for integer constants /2、これらのマクロで非定数を使用することにも注意する必要があります。それらは動作することが保証されていません。

これらのマクロのインスタンスの引数は、対応する型の制限を超えない値を持つ接尾辞なしの整数定数 (6.4.4.1 で定義) でなければなりません。

6.4.4.1さまざまな整数形式 (10 進数/8 進数/16 進数) をさまざまな接尾辞 ( UULULLLおよびLL型に応じて対応する小文字) と共に指定するだけです。肝心なのは、変数ではなく定数でなければならないということです。

たとえば、次のglibcとおりです。

# define INT8_C(c)      c
# define INT16_C(c)     c
# define INT32_C(c)     c
# if __WORDSIZE == 64
#  define INT64_C(c)    c ## L
# else
#  define INT64_C(c)    c ## LL
# endif

これにより、INT8_Cマクロは正常に機能しますが、テキストINT64_C(val)は前処理されてvalLまたはvalLLになり、どちらも必要ありません。

于 2011-10-04T02:09:22.070 に答える
17

#ifプリプロセッサ ディレクティブで結果を有効にするという、ここでの単項プラス演算子の要点を誰もが見逃しているようです。与えられた:

#define INT8_C(val) ((int8_t) + (val))

ディレクティブ:

#define FOO 1
#if FOO == INT8_C(1)

次のように展開します。

#if 1 == ((0) + (1))

したがって、期待どおりに動作します。これは、ディレクティブ#define内の un d シンボルが に展開されるためです。#if0

単項プラス (#ifディレクティブでバイナリプラスになる) がなければ、式はディレクティブで有効ではありません#if

于 2011-10-04T05:12:16.843 に答える
10

単項演算+子です。オペランドの値を生成しますが、算術型にのみ適用できます。ここでの目的はINT8_C、ポインター型の式での使用を防ぐことです。

しかし、あなたの声明表現

INT8_C(val);

未定義の動作があります。への引数INT8_C()は、「接尾辞なしの整数定数 ... 対応する型の制限を超えない値を持つ」必要があります ( N1256 7.18.4)。これらのマクロの目的は、次のようなものを記述して、 if isやif is `long long などにINT64_C(42)展開できるようにすることです。42Lint64_tlong42LLint64_t

しかし、どちらかを書く

((int8_t) + (78));

また

((int8_t) + (val));

あなた自身のコードでは完全に合法です。

編集

INT8_C()質問の定義:

#define INT8_C(val) ((int8_t) + (val))

C99 では有効ですが、後の N1256 ドラフトによると、技術正誤表の 1 つが変更された結果、非準拠です。

元の C99 標準、セクション 7.18.4.1p2 には、次のように記載されています。

マクロINT***N* _C**( value ) は、指定された値とタイプint_least***N* _t**を持つ符号付き整数定数に展開されます。

N1256 はこれを (段落 3) に変更しました。

これらのマクロのいずれかを呼び出すたびに、#if前処理ディレクティブでの使用に適した整数定数式に展開されます。式の型は、対応する型の式が整数昇格に従って変換される場合と同じ型を持つ必要があります。式の値は、引数の値になります。

この変更は、不具合レポート #209に対応して行われました。

EDIT2:しかし、R..の答えを見てください。かなりあいまいな理由で、実際には N1256 で有効です。

于 2011-10-04T02:11:19.900 に答える
0

それは単項プラスです。

それができることは2つだけです。

  1. 通常の算術変換として知られているものをオペランドに適用します。これにより、結果の共通の実数型が確立されます。結果が特定のものにキャストされようとしている場合、これを強制する理由は考えられません。

  2. オペランドを、算術演算子が定義されている型に制限します。これがもっともらしい理由のようです。

于 2011-10-04T02:23:04.157 に答える