特定の型 (たとえばint、char、float、 ..) へのポインターがインクリメントされると、その値はそのデータ型のサイズだけ増加します。voidサイズのデータを指すポインターがインクリメントされる場合x、どのようにしてxバイト先を指すようになりますか? xコンパイラーは、ポインターの値に追加することをどのように認識しますか?
9 に答える
最終的な結論: a の演算はvoid*、C と C++ の両方で違法です。
GCC では、拡張機能としてこれを使用できます。 - および関数ポインターの算術演算をvoid参照してください(このセクションは、マニュアルの「C 拡張機能」の章の一部であることに注意してください)。Clang と ICCvoid*では、GCC との互換性のために算術演算が許可されている可能性があります。他のコンパイラ (MSVC など) は での算術演算を許可しません。GCCは、フラグが指定されている場合、またはフラグが指定されvoid*ている場合は許可しません(このフラグは、コード ベースも MSVC でコンパイルする必要がある場合に役立ちます)。-pedantic-errors-Werror-pointer-arith
C標準は語る
引用は n1256 ドラフトから取得されます。
加算操作の標準の説明には、次のように記載されています。
6.5.6-2: 加算の場合、両方のオペランドが算術型であるか、一方のオペランドがオブジェクト型へのポインタで、もう一方が整数型である必要があります。
したがって、ここでの問題void*は、 が「オブジェクト型」へのポインタであるかどうか、または同等に「オブジェクト型」であるかどうかvoidです。「オブジェクト タイプ」の定義は次のとおりです。
6.2.5.1: 型は、オブジェクト型(オブジェクトを完全に記述する型)、関数型(関数を記述する型)、および不完全型(オブジェクトを記述するが、サイズを決定するために必要な情報が不足している型) に分割されます。
また、標準では次のように定義voidされています。
6.2.5-19:
void型は値の空のセットで構成されています。完成できない不完全型です。
は不完全型なのでvoid、オブジェクト型ではありません。したがって、これは加算演算の有効なオペランドではありません。
したがって、ポインターに対してポインター演算を実行することはできませんvoid。
ノート
当初void*は、C 標準の次のセクションにより、算術演算が許可されていると考えられていました。
6.2.5-27: voidへのポインターは、文字型へのポインターと同じ表現およびアラインメント 要件を持たなければなりません。
でも、
同じ表現とアラインメントの 要件は、関数への引数、関数からの戻り値、および共用体のメンバーとしての互換性を暗示するものです。
したがって、これはが型またはをprintf("%s", x)持っていても同じ意味を持つことを意味しますが、 で算術演算を実行できるという意味ではありません。xchar*void*void*
ポインタ演算はポインタでは許可されていませんvoid*。
それを char ポインターにキャストし、ポインターを x バイト先にインクリメントします。
void *まさにこの理由で、型に対してポインター演算を行うことはできません!
void ポインタは、任意のメモリ チャンクを指すことができます。したがって、コンパイラは、void ポインターでポインター演算を試行するときに、インクリメント/デクリメントするバイト数を知りません。したがって、void ポインターは、ポインター演算に関与する前に、まず既知の型に型キャストする必要があります。
void *p = malloc(sizeof(char)*10);
p++; //compiler does how many where to pint the pointer after this increment operation
char * c = (char *)p;
c++; // compiler will increment the c by 1, since size of char is 1 byte.
ポインター演算を行う前に、別の型のポインターにキャストする必要があります。
コンパイラは型キャストで認識します。与えられたvoid *x:
x+1に 1 バイトを加算しx、ポインタはバイトに移動しますx+1(int*)x+1バイトを追加しsizeof(int)、ポインターはバイトに移動しますx + sizeof(int)(float*)x+1アドレスsizeof(float)バイトなど
最初の項目は移植性がなく、C/C++ の Galateo に反していますが、それでも C 言語に正確です。つまり、ほとんどのコンパイラで何かにコンパイルされ、適切なフラグ (-Wpointer-arith など) が必要になる可能性があります。