異なるコンパイラーでのvoid **への変換


9

次のコードをさまざまなコンパイラで実行しています。

int main()
{
    float **a;
    void **b;
    b = a;
}

私が収集できたことから、汎用ポインタでvoid **はありません。これは、別のポインタからの変換がコンパイルされたり、少なくとも警告をスローしたりしないことを意味します。しかし、ここに私の結果があります(すべてWindowsで行われます):

  • gcc-期待どおりに警告をスローします。
  • g ++ -予想どおりエラーをスローします(これは、C ++の型の許容度が低いためです)。
  • MSVC(cl.exe) -/ Wallが指定されていても、警告は一切表示されません。

私の質問は、全体について何か不足しているのですか?MSVCが警告を生成しない特定の理由はありますか?MSVC から void **への変換時に警告を生成しfloat **ます。

もう1つの注意点:a = b明示的な変換に置き換えた場合a = (void **)b、どのコンパイラも警告をスローしません。これは無効なキャストだと思ったので、なぜ警告がないのでしょうか?

私がこの質問をしているのは、CUDAと公式のプログラミングガイド(https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory)を学び始めていたからです次のコードが見つかります:

// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);

の最初の引数は型であるvoid **ため&d_A、これはfor への暗黙の変換を実行する必要cudaMallocがありvoid **ます。同様のコードがドキュメント全体にあります。これはNVIDIAの終わりのずさんな作業ですか、それとも私は何か不足していますか?nvccはMSVCを使用しているため、コードは警告なしでコンパイルされます。


3
投稿された3つのライブのエラー:godbolt.org/z/GQWMNo
Richard Critten

3
MSVCでのコードエラー。どのバージョンを使用していますか?しかし、はい、void**一般的なポインタではありません。だけvoid*です。
NathanOliver

素早い回答ありがとうございます!19.24.28315 for x64はどうですか?これまでにMSVCを実際に使用したことはありません。
CaptainProton42

2
(void**)明示的なcスタイルのキャストです。これは、コンパイラに、実行中のことを注意深く見ないで、信頼するように指示します。これはタイプセーフシステムの明示的なオーバーライドであり、コンパイラは基本的にあらゆる種類の変換を受け入れる必要があります。Cスタイルのキャストは避けてください。非常に強力です。static_cast意味のないことをしようとすると文句を言うようなC ++キャストを使用します。
フランソワアンドリュー

@RichardCritten間違った言語-エラーなしgodbolt.org/z/RmFpgN C ++ cudaは通常どおり明示的なキャストを必要とします。
P__J__

回答:


4

全体について何か不足していますか?MSVCが警告を生成しない特定の理由はありますか?MSVCは、void **からfloat **に変換するときに警告を生成します

キャストのないこの割り当ては制約違反であるため、標準に準拠したコンパイラーは警告またはエラーを出力します。ただし、MSVCは完全にCに準拠していません。

もう1つの注意点:a = bを明示的な変換a =(void **)bで置き換えると、どのコンパイラーも警告をスローしません。これは無効なキャストだと思ったので、なぜ警告がないのでしょうか?

一部の状況では、キャストを介したポインター変換が許可されています。C規格では、セクション6.3.2.3p7で次のように述べています。

オブジェクト型へのポインタは、別のオブジェクト型へのポインタに変換される場合があります。結果のポインターが参照される型に対して正しく配置されていない場合、動作は未定義です。それ以外の場合、再度変換すると、結果は元のポインタと同じになります。オブジェクトへのポインターが文字型へのポインターに変換されると、結果はオブジェクトのアドレス指定された最下位バイトを指します。オブジェクトのサイズまで、結果を連続的にインクリメントすると、オブジェクトの残りのバイトへのポインターが生成されます。

したがって、位置合わせの問題がなく、元に戻すだけの場合は、ポインター型間で変換できます(ターゲットがでない限りchar *)。

float* d_A;
cudaMalloc(&d_A, size);

...

これはNVIDIAの終わりのずさんな作業ですか、それとも私は何か不足していますか?

おそらく、この関数は指定されたポインタを逆参照して、割り当てられたメモリのアドレスを書き込んでいます。それはfloat *、あたかものようにに書き込もうとしていることを意味しvoid *ます。これは、との間の一般的な変換とは異なりvoid *ます。厳密に言えば、これは未定義の動作のように見えますが、最新のx86プロセッサー(リアルモードでない場合)はすべてのポインター型に同じ表現を使用するため、「動作」します。


@dbush非常に有益です、ありがとうございます!動作する場合、なぜ動作するかがわかります。それでも、&d_A必要な型がないため、ほとんどのコンパイラは警告やエラーをスローしませんか?
CaptainProton42

3
これをどのように解釈するかに注意してください。C++コンパイラを使用してCUDAをコンパイルする場合、テンプレートトリックが存在する可能性があり、そのトリックがあります
talonmies
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.