0

これは少し長いことは承知していますが、難しい問題です。ご覧いただきありがとうございます。私はこれにあまりにも長い間取り組んできました。私は多くの調査を行い、多くのことを試しました。誰かが説明を手伝ってくれることを願っています.

概要:

C で書いています。計測器からデータの配列を取得する必要があります。配列のサイズは、収集されるデータの量によって異なります。データポイントの数を照会できます。データを収集する関数を作成しました (以下を参照)。これは、関数が main() で直接呼び出されたときに機能します。テストに使用します。ただし、この関数は dll であり、上位の dll 内の関数から呼び出されます。これは動作しません。可変サイズのためだと思います。

変数のサイズとポインタの詳細に迷っています。どんな助けでも大歓迎です。

main() から呼び出される機能コード

*Note - Below ViInt16 is a signed short type specific to VISA (communication protocol for instrument). Function returns an int as the status/error (set in other code).

header:

    int GetSamples (ViInt16 *DataArray, int DataSize);

function:

    int GetSamples (ViInt16 *DataArray, int DataSize)
    {
        ViUInt16 N=0;
        ViInt16 Datatemp[DataSize];

        viMoveIn (Handle, N, 0, DataSize, Datatemp);
        memcpy (DataArray, Datatemp, sizeof(Datatemp);
    }

main:

    int totalsamples = (PreTrigPts() + AcqPts())
    ViInt16 Data [totalsamples];
    GetSamples (Data, totalsamples);             

This works! I think, only because I can get the total size and then allocate the ViInt16 array from main(). Truthfully, not sure what I'm doing with the pointers, etc. in passing around arrays

The problem is, I'm not sure what to do when it's a function calling a function because, I think, the array needs to be allocated at the top, before I've queried the size. Here is how I am trying to do it (that's not working)

Problem Code

Low level "driver" (called as a dll):

    Header and function definition from above.

Functions_header: (what calls the low level driver as dll)

    void AutoSample(void);  //No returns. Writes to UI in Functions_list.c

Function_list.c:

    void AutoSample ()
    {
        int PreTriggerPts = 0;  //Declare all variables at top, or won't compile
        int Points = 0;
        int TotalSamples = 0
        ViInt16 MyData [5] = {0};  //arbitrary since don't know size yet

        TotalSamples = (PreTrigPts() + AcqPts());

        ViInt16 MyData[TotalSamples];  //Trying to size by reinitializing? 

        GetSamples (MyData, TotalSamples);

        //...calls another function to write MyData to UI...etc. etc.

Main.c:

    AutoSample();

Errors

いろいろ試したのでエラーが多発しました。必要に応じて、より具体的にすることもできますが、変数のサイズがわかった後で (作業コードで行ったように) 変数を初期化しようとすると、それは違法であることがわかります。宣言を一番上に置くと、それが修正されます。初期化するサイズがわかりません。ここから、私はハッキングしてきました。具体的なことはありません。ポインターとメモリでやらなければならないことがありますが、何がわかりません。どうぞ、どんな助けでも大歓迎です!

4

4 に答える 4

0

いくつかのこと。

これを AutoSample で試してください (メインと同様):

void AutoSample ()
{
    int PreTriggerPts = 0;  //Declare all variables at top, or won't compile
    int Points = 0;
    int TotalSamples = (PreTrigPts() + AcqPts());
    ViInt16 MyData[TotalSamples];  //Trying to size by reinitializing? 

    GetSamples (MyData, TotalSamples);

    //...calls another function to write MyData to UI...etc. etc.

また、GetSamples() では、memcpy() を回避できます。

int GetSamples (ViInt16 *DataArray, int DataSize)
{
    ViUInt16 N=0;

    viMoveIn (Handle, N, 0, DataSize, DataArray);
}
于 2013-05-31T19:15:19.273 に答える
0

必要な要素の数がわかるまで、VLA の宣言を延期できるはずです1 :

void AutoSample ()
{
    int PreTriggerPts = 0;  
    int Points = 0;
    int TotalSamples = 0

    TotalSamples = (PreTrigPts() + AcqPts());

    ViInt16 MyData[TotalSamples];     // initializer not allowed for VLAs
                                      // If you *really* need to initialize a VLA,
                                      // use memset or memcpy

    GetSamples (MyData, TotalSamples);

    //...calls another function to write MyData to UI...etc. etc.

そうでない場合は、コンパイラにフラグを設定して、宣言とコードの混合を許可する必要がある場合があります。

ポインタと配列について...

ほとんどの場合、「N-element array of T」型の式は「pointer to」型の式に変換され、式の値は配列2Tの最初の要素のアドレスになります。この規則の例外は、式がまたは 単項演算子のオペランドである場合、または別の配列を初期化するために使用される文字列リテラルである場合に発生します。 sizeof&

したがって、関数呼び出しで

GetSamples (MyData, TotalSamples);

は型 " -element array of " から型 "pointer to " にMyData変換され、が受け取る値はの最初の要素へのポインターです。これが、関数宣言が次のように記述される理由です。TotalSamplesViInt16ViInt16GetSamplesMyData

int GetSamples (ViInt16 *DataArray, int DataSize);

実際GetSamplesに受け取るのは配列ではなくポインター値であるためです。次のように書くこともできます

int GetSamples (ViInt16 DataArray[], int DataSize);

関数パラメーター宣言のコンテキストでは、T a[]T a[N]は と同等T *aです。これは、関数パラメーター宣言に のみ当てはまることに注意してください。

VLA は便利ですが、制限があります。

  • ファイル スコープ (関数の外) で使用することも、宣言することもできませんstatic
  • 通常の配列初期化構文では初期化できません。
  • 名前にもかかわらず、その場でサイズを変更することはできません。
  • 任意に大きくすることはできません。
  • それらは普遍的にサポートされているわけではなく、C2011 標準の時点ではオプションです。

malloc返されるサンプルの数によっては、VLA を破棄して、またはを使用してヒープからメモリを割り当てることができますrealloc


1 - C99 では、宣言とコードを混在させることができます。VLA を正常に使用している場合は、C99 以降のコンパイラを使用している可能性が高くなります。
2 - 信じられないかもしれませんが、この動作には合理的な説明があります。「Embryonic C」というタイトルのセクションまでスクロールしてください。

于 2013-05-31T20:52:28.277 に答える
0

次のように、ViInt16 MyData を配列ではなくポインターにする必要があると思います。

 ViInt16 *MyData;

次に、データの長さがわかったら、次のようにバッファを動的に割り当ててデータを保持します。

 MyData = (ViInt16*)malloc((sizeof ViInt16) *  TotalSamples); 

後で free を呼び出して、このバッファを解放する必要があることに注意してください。

于 2013-05-31T18:56:07.643 に答える