2011-02-21 33 views
1

構造体に埋め込まれていると、C言語の新機能で配列型に問題があります。以下は私の問題の一例です:構造体内の配列

typedef struct { 
    double J[151][151]; 
} *UserData; 

static int PSolve(void *user_data, N_Vector solution) 
{ 
UserData data; 
data = (UserData) user_data; 

double J[151][151]; 
J = data->J; 

/* Solve a matrix equation that uses J, stored in 'solution' */ 

return(0); 
} 

私はこれをコンパイルしようとすると、私は エラーが出る:型に割り当てる際のタイプから「ダブル[151] [151]」互換性のない型「をダブル(*)[ 151] '

現在の回避策は、行列式を解くために' J [x] [y] 'をコードの' data-> J [x] [y] 'に置き換えることでしたが、効率が悪いことを示しています。

引数の型と順序を規定するsundials-cvodeソルバーを使用しているため、PSolveへの引数の変更はオプションではありません。

は、助けを求め アンドリューありがとう

+0

[C配列の宣言と代入の可能な複製?](http://stackoverflow.com/questions/744536/c-array-declaration-and-assignment) – outis

+0

'data-> J'をローカル配列にコピーするのではなく、あるいは、あなたはその機能の中でそれを修正していますか? –

+0

私は回避策として、私は行列式でデータ→J [x] [y]を読みとっていると言いました。しかし、この機能は実行中に数十億回呼び出されます。データ - > Jはパフォーマンスのボトルネックに見えます。回避策としてローカルコピーを取得しようとしています。 – Sevenless

答えて

5
typedef struct { 
    double J[151][151]; 
} UserData; // This is a new data structure and should not a pointer! 

static int PSolve(void *user_data, N_Vector solution) 
{ 
UserData* data; // This should be a pointer instead! 
data = (UserData*) user_data; 

double J[151][151]; 
memcpy(J, data->J, sizeof(double) * 151 * 151); // use memcpy() to copy the contents from one array to another 

/* Solve a matrix equation that uses J, stored in 'solution' */ 

return(0); 
} 
+0

'memcpy()'で単に 'sizeof J'を使うことができます。 – caf

+0

新しい構造定義を反映するようにコードを更新しました。しかしmemcpy()は、ローカルコピーを持たず、J [x] [y]をdata-> J [x] [y]と参照するのに比べて、合計計算時間の約20%を追加したため、実行可能なオプションではありません。主な問題はデータ - > Jがボトルネックに見えているので、@cafのキーワード 'restrict'を使うことを提案しようと思います。 – Sevenless

+0

構造体をポインタにしないようにするための+1。なぜ私は完全にはわかりませんが、プログラム内の他の場所で操作をやめてしまいました。 – Sevenless

-1

double **Jとしてローカル変数double J[151][151]を定義してみます。

+0

ダイスがない場合、互換性のないポインタ型についての警告とともにコンパイルされますが、実行時には重大なエラーが発生します。試してくれてありがとう。 (私は-1ではありませんでした) – Sevenless

0

配列に割り当てることはできません。

double (*J)[151] = data->J; 

151の配列へのポインタです:あなたは、あなたのコード内で必要なもの

C.

における配列とポインタの違いについては、このようなだけで何かで調べる必要があります。あなたがすべてだのtypedef

typedef double line[151]; 
line *J = data->J; 

てみたい場合は、あなたはデータをコピーしますが、データへのポインタだけではないはずです。

編集:しかし、回答のスレッド全体を見て、私はそのすべてがあなたのボトルネックがあるかもしれない、純粋な憶測だと思います。たとえば、あなたが「間違った方法で丸ごと」、列方向にアクセスしているなど、どこにいてもかまいません。あるいは、メモリからデータをポンピングすることは、あなたの計算を支配しているだけです。

おそらく、あなたのコンパイラが生成するアセンブラ(オプション-S)を調べて、何か怪しいものがあるかどうかを調べることを検討してください。

+0

これは後で 'data-> J'を関数の中で直接使用するように動作する可能性はほとんどありません。 – caf

+0

@cafの場合、間接的に1つ少ないです。したがって、 'data'が実際にどのように宣言されるかによって異なります。 –

+0

@caf @ Jens-Gustedt:質問を編集して、UserDataのtypedefを含め、質問のパフォーマンス要素を明確にしました。 – Sevenless

2

問題の根本原因は、Cで配列タイプを直接割り当てることができないことです。memcpy()を明示的に使用する必要があります。karlphillip's answerが表示されます。

ただし、コピーを実行すると、残りの機能で行った最適化の効果がなくなる可能性があります。恐らくsolution引数はポインタであり、オプティマイザはuser_data/datasolutionの間の潜在的なエイリアシングを心配しています。あなたはC99のrestrictキーワードをサポートコンパイラを持っている場合は別の方法として、引数にその修飾子を使用することです:

static int PSolve(void * restrict user_data, N_Vector restrict solution) 

これは、これらのポインタがないエイリアスを行うコンパイラを約束し、あなたが直接できるようにする必要がありますコンパイラの最適化を犠牲にすることなくdata->Jを使用してください。

キーワードは、__restrictなどのスペルでC89モードで使用できます。詳細については、コンパイラのドキュメントを参照してください。

+0

私は 'gcc44 -c -std = C99 -I/home/matteson/sundials/include/C99でコンパイルすると、restrictキーワードを追加しましたが、cc1:error:認識できないコマンドラインオプション" -std = C99 " -I/misc/linux/64/opt/pkg/matlab/R2010b/extern/include -I/misc/linux/64/opt/pkg/matlab/R2010b/simulink/include -DMATLAB_MEX_FILE -D_GNU_SOURCE -fexceptions -fPIC -fno -omit-frame-pointer -pthread -fopenmp -DMX_COMPAT_32 -O3 -DNDEBUG "het_kry.c" 'gccのマンページを調べて、それが正しいフラグだと言います。 – Sevenless

+1

@Sevenless:小文字の "c" - '-std = c99'です(実際には' -std = gnu99'が標準のデフォルト 'gnu89'のC99バージョンです)。 – caf

+0

ありがとう、 Sevenless