2013-03-05 11 views
5

私はgccでvoid *とchar *はポインタの算術演算に関して同じように扱われると考えました。つまり、void *は "メモリ内の1バイトに"指しているので、次のコードC voidポインタの算術

void *p; 
p = malloc(sizeof(void)); 
printf("%p %p\n",p,p+1); 

実際には0x984a008 0x984a009が返されます。ポインタと同様に、ボイド**点、そうずつ増分は実際に、すなわち、4バイト(32ビットOS上で)によって

void **p; 
p = (void **) malloc(sizeof(void *)); 
printf("%p %p\n",p,p+1); 

戻り0x984a008 0x984a00cの増加を意味します。それが再び0x984a008 0x984a009返すのでしかし、次のコードは、私に

void **p, *p1; 
p = (void **) malloc(sizeof(void *)); 
p1 = (void **) p; 
printf("%p %p\n",p1,p1+1); 

を混乱させる。ここで何が起こっているのですか?

+2

おそらく、あなたは 'void型を意図** P、** P1を、代わりに' 'void ** p、* p1;'? –

+1

'sizeof(void)'は1であるか、少なくとも警告を出しますが、無駄です。あなたはそれをしません。 'void '型は何を表しますか? 'void * 'しかありません。 –

+0

私はvoid ** p、* p1を意味しました。私はこのコードがコンパイルされていることを知っていますが、pが当初はvoid **として宣言されていて、p + 1が4バイト分のインクリメントに対応し、p1がvoid *算術演算はp1 + 1に対して1バイトしか追加しません。 – Ivan

答えて

1

voidポインタはインクリメントできません。これは未定義の動作です。

関連質問: Increment void pointer by one byte? by two?

+0

OKですが、すべての型を 'char'ポインタに変更しても問題は解決しません(ただし、GCCでは警告が表示されますが、値のカテゴリの影響は無視されます)。その場合) – Rup

2

あなたはvoid *で動作するときは、void **を使用する場合、増分は1で、それはポインタのサイズです。

あなたを混乱させる操作では、void *をキャストしてvoid **にキャストすると、暗黙のうちにvoid *に戻されます。あなたがintbをキャスト

long a, b, c; 
c = a + (int) b; 

が、その後、あなたは、それがバックキャストですので、longで動作するようにしたい:あなたはこれをしなかったかのようです。

+0

それは問題ありませんが、なぜコンパイラは再作成を行いますか? 'void *'と 'void ** 'の両方がスタック上で4バイトをとり、私が理解する限り、すべてのポインタの算術演算はコンパイル時に行われます。ではコンパイラはなぜp1がキャストバックされていると主張していますか? – Ivan

+0

このように考えてみましょう。 'void ** 'を' void *'にキャストすることは理にかなっています。どのポインタも 'void * 'になる可能性があります。反対に、他の方法でキャストすると、そうしない。すべてのポインタがダブルポインタであるわけではありません。コンパイラは、要求された操作で敏感なことを行います。 – slezica

7

p1のタイプがあるvoid * ...

を一瞬voidポインタ演算の可能な未定義の動作を無視します。

異なるタイプの値を割り当てることによって、変数のタイプを変更することはできません。 p1は常にvoid *のままです。

それに割り当てられた異なる型の式は暗黙的にvoid *にキャストされます(できない場合はエラーを返します)。

したがって、基本的には最初の例と同じです。

EDIT:

は、私の知る限りでは、実際に何もしない別のポインタ型からキャストし、その主な目的は、型チェックのためです。

ポインタはとても基本的にメモリのようなものに見える、ちょうどメモリアドレス、番号である:(ポスト割り当てを)

p1  p2 
void * void** <- these types are fixed and known during compilation 
------ ------ 
|1234| |1234|   at address 1234 = the 4 bytes from malloc 
------ ------ 
^
    | 
this value is the only thing that will change by assigning p1 to a different value 
+3

一部のアーキテクチャでは、あるポインタ型から別のポインタ型へのキャストは何かを変更します。しかし、典型的なx86(_64)アーキテクチャでは、すべてのポインタが同じ表現を持ち、キャストがノーオペレーションであると期待できます。 –

3

voidへのポインタに対する演算であるためあなたは、char *代わりのvoid *を使用する必要がありますgcc拡張。

char *p1 = /* ... */; 

printf("%p %p\n", p1, p1+1); 

どんな点ppにポインタ演算がchar *タイプ(char **ない)を使用します。

あなたが書く場合:

char *p1 = /* ... */; 

printf("%p %p\n", p1, (char**)p1+1); 

ポインタ演算はchar **を使用しています。

0

私は1年以上後に投稿していることを知っていますが、私はこの質問を受け取り、それが私を興味をそそられました。

@Dukelingに同意すると、変数の型をキャストするだけでは変更できません。しかし、それはコンパイラがvoidとみなすものに依存するようです。このサンプルプログラムを見て、結果の出力を見てください。 vpvp2の唯一の違いは、malloc()の部分のsizeof()です。 gcc (Debian 4.7.2-5) 4.7.2
コンパイル行:上でコンパイル

gcc -o void_test void_test.c

#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char **argv) { 
    void *vp, *vp2; 

    printf("sizeof(void) = %d\n", sizeof(void)); 
    printf("sizeof(void *) = %d\n", sizeof(void *)); 
    printf("sizeof(char) = %d\n", sizeof(char)); 
    printf("sizeof(char *) = %d\n\n", sizeof(char *)); 

    vp = (void *) malloc(sizeof(void)); 
    vp2 = (void *) malloc(sizeof(void *)); 

    printf("vp = %p\n", vp); 
    printf("vp+1 = %p\n", vp+1); 
    printf("vp2 = %p\n", vp); 
    printf("vp2+1 = %p\n", vp2+1); 

    return 0; 
} 

は、次のような出力が得られます。

$ ./void_test 
sizeof(void) = 1 
sizeof(void *) = 8 
sizeof(char) = 1 
sizeof(char *) = 8 

vp = 0x1ee3010 
vp+1 = 0x1ee3011 
vp2 = 0x1ee3010 
vp2+1 = 0x1ee3031 
関連する問題