2016-10-16 6 views
3

p[i]ここで、char *p;はグローバル変数です。次のようにポインタアクセスへのインデックス付きアクセスの切り替え

char *p; 
int access_p_i(uintptr_t i) 
{ 
    return printf("p[%lx]=%c\n", i, p[i]); 
} 

使用目的は次のとおりです。

char buf[] = "abcde"; 
p = buf; /*set p once*/ 
access_p_i(3); //prints p[3]=d 
access_p_i(2); //prints p[2]=c 

は、私は絶対的なポインタを取るために(機能を変更することなく)、それをハイジャックしたいと言う:

memset(&p,0,sizeof(char*)); /*set p once*/ 
access_p_i((uintptr_t)"d"); 
access_p_i((uintptr_t)"c"); 

これはポータブルだろうと法的なC?

+0

@ 2501私が本当にやりたいことは、そのポインタを構造体に持っていて、その構造体を主にインデックスを使って操作する機能が1つありますが、それを生ポインタに切り替えることがあります両方のケースでただ1つの関数を使うことができるかどうか疑問に思っています(私はそれらを格納するのでインデックスを使用し、ベースが再配置されている場合は書き直す必要はありません)。 – PSkocik

+1

@ 2501それはうまく動作することはありませんが、完全にうまく動作します([demo](http://ideone.com/b10yMu))。 – dasblinkenlight

+2

@dasblinkenlightそれは未定義の動作ではありません。標準は動作を定義し、コンパイラの出力は定義しません。 Gccはここでは非常に寛容です。 – 2501

答えて

1

インデックスa[b]i[p]p[i]通常と逆の間で奇数等価につながる、別の*(a+b)を書く方法や*(b+a)それと同等であるため、インデックス付きのアクセスの背後にある数学は、作業を継続していきます。

ただし、標準ではchar*を損失なしでsize_tに変換できるという保証はないため、このコードは移植性がありません。私はuintptr_tは、ターゲットシステム上で利用可能であると仮定すると、uintptr_t

ですべてsize_tを交換した場合、あなたはp = (char*)(uintptr_t)0割り当てとmemset(&p,0,sizeof(char*))呼び出しを変更する必要がありますどのような

。しかし、ほとんどのシステムでは重要ではありません。

0

ISO/IEC 9899:1999 7.18.1.4はintptr_tuintptr_tがオプションであることを言うと、7.18/4:

実装は、これらのタイプは、 "必須" として記述し提供するものとするが、いずれかを提供する必要はありません(「オプション」と記載されています)。

2

いいえ、私はそれは問題ないと思います。 ANSI/ISO 9899-1990から、追加またはポインタに/から整数を減算約:

場合の最後の要素過去ポインタオペランドと同じ配列オブジェクトの要素を結果ポイント、または1つ両方配列オブジェクト、評価はオーバーフローを生成してはならない。それ以外の場合、動作は未定義です。ポインタのオペランドと結果が同じ配列オブジェクトの要素を指し示すか、ポインタのオペランドが配列オブジェクトの最後の要素を1つ指し、結果が同じ配列オブジェクトの要素を指している場合を除き、結果は単項演算子のオペランドとして使用されます。

+1

しかし、OPの場合、オペランドと結果の両方が同じ配列オブジェクトの要素を指しています(この場合、文字列リテラル内の文字の配列です)。 – dasblinkenlight

+2

@dasblinkenlight *ポインタのオペランドと結果が同じ配列オブジェクトの要素を指していない限り、*ポインタと結果は*両方とも*同じ*オブジェクトを指していません。ポインタはNULLポインタであるためオブジェクトを指さず、結果はオブジェクトを指します。 – 2501

+1

つまり、ポインタ演算の必要条件は、ポインタと結果の両方が同じオブジェクトを指すことです。そうでない場合、動作は未定義です。 – 2501

関連する問題