0

固定の 14 文字の開始文字とさまざまなコンテンツで終了する文字列 (正確に char 配列) を作成しようとしています。可変ビットには、2 つの浮動小数点数と 1 つの 32 ビット整数が含まれており、配列内でコンマで区切られた 4 つの 1 バイト文字として個別に扱われます。次のコードは、いくつかの明白な理由 (*char を *float に代入できない) でコンパイルされていないことを示しています。それで、それを回避するにはどうすればよいですか?

char *const comStr = "AT+UCAST:0000=0760,0020,0001\r"; // command string

float *pressure;
float *temperature;
uint32_t *timeStamp;

pressure = comStr + 14; // pressure in the address following the '=' in command string

temperature = comStr + 18; // temperature in the address following the 1st ',' in command string

timeStamp = comStr + 22; // time stamp in the address following the 2nd ',' in command string

C 言語の struct や union のような、変数が「構造体」内で定義されるメモリ割り当て順序を厳密に予約するものについては、記憶が定かではありません。多分このようなもの:

typedef struct
{
  char[14] command;
  float *pressure;
  char comma1;
  float *temperature;
  char comma2;
  uint32_t *time_stamp;
  char CR;
}comStr;

この構造は、comStr-> command[15] が *pressure の最初/最後のバイト (エンディアンによって異なります) を与えることを保証しますか? それとも、私からトリックを隠す特別な構造が他にありますか?

(注: comStr-> command[15] は将来のコードでは評価されないため、ここではインデックス境界を超えることは問題になりません。ここで唯一重要なことは、ハードウェア フェッチが持続するようにメモリが継続的に割り当てられているかどうかだけです。メモリ アドレス (comStr-> コマンド) から始まる 29 バイトの場合、必要な文字列が正確に得られます)。

psこれを書いているときに、私はアイデアを思いつきました。目的のために memcpy() を使用することはできますか ;) memcpy には void* タイプのパラメーターがあります。今からやってみます!とにかく、すべての雹stackOverflow!

編集:誤解を招き、誤解を招いて申し訳ありません。作成したい文字配列は、UART を介してバイト単位で送信されます。これを行うには、文字配列の開始メモリ アドレスと長さが DMA システムに与えられている場合、DMA システムを使用して、配列をバイトごとに自動的に送信バッファに転送します。したがって、文字配列はメモリに継続的に格納する必要があります。これで質問がより明確になることを願っています。

4

3 に答える 3

1

あなたの質問でカバーされるさまざまな問題。私はそれらの問題のいくつかを取り上げます。

  • 構造体のメンバーの順序は、宣言した順序と同じであることが保証されています。しかし、ここには別の問題があります - パディングです。これを確認してください - http://c-faq.com/struct/padding.html他のリンク/質問に従ってください
  • 次に、「125」のようなものは整数であるとか、「1.25」のようなものは浮動小数点数であると誤解していることです。そうではなく、文字列です。すなわち

    char * p = "125";
    

    p[0] には 0 は含まれません。「0」が含まれます。エンコーディングが ASCII の場合、これは 48 になります。つまり、p[0] には 48 が含まれ、0 ではありません。p[1] には 49 と p[ が含まれます。 2] には 52 が含まれます。float の場合も同様です。

反対のことも起こります。つまり、アドレスがあり、それを char 配列として扱う場合、char 配列には、予想される float が含まれません。これを確認するには、このプログラムを試してください

#include <stdio.h>

struct A
{
    char c[4];
    float * p;
    int i;
};

int main()
{
    float x = 1.25;
    struct A a;
    a.p = &x;
    a.i = 0; // to make sure the 'presumed' string starting at p gets null terminate after the float
    printf("%s\n", &a.c[4]); 
}

私の場合は「╪・↓」と表示されます。そして、これはエンディアンとは何の関係もありません。

  • 構造体オブジェクトに値を割り当てるときに覚えておく必要があるもう 1 つのこと - comStr.pressure と comStr.temperature がポインターであることを覚えておく必要があります。それらに値を直接割り当てることはできません。それらに既存のフロートのアドレスを与えるか、それらが指すことができるメモリを動的に割り当てる必要があります。

また、char 配列を作成しようとしているか、すでに存在する char 配列を解析しようとしていますか。あなたがそれを作成しようとしている場合、これを行うためのより良い方法はsnprintf、あなたが望むことを行うために を使用することです. snprintfと同様の書式指定子を使用しますprintfが、char 配列に出力します。その方法で char 配列を作成できます。作成したこの char 配列をどうするつもりなのか、エンディアンが適切かどうかを判断する、より大きな問題が残ります。

与えられた char 配列から読み取ろうとしていて、フロートやコンマなどに分割しようとしている場合、これを行う 1 つの方法はsscanf、特定の文字列形式では難しい場合があります。

于 2013-04-14T03:54:57.370 に答える
1

この提案された構造:

typedef struct
{
  char[14] command;
  float *pressure;
  char comma;
  float *temperature;
  char comma;
  uint32_t *time_stamp;
  char CR;
}comStr;

あなたの要件を助けるつもりはありません:

ここで唯一重要なことは、メモリ アドレス ( comStr->command) から始まる 29 バイト続くハードウェア フェッチによって、必要な文字列が正確に得られるように、メモリが継続的に割り当てられているかどうかだけです。

同じ名前のメンバーを 2 つ持つことはできないことに注意してください。たとえばcomma1、 andを使用する必要があります。comma2また、配列の次元が間違った場所にあります。

1 つの問題は、構造内にパディング バイトが存在することです。

もう 1 つの問題は、ポインターが構造体の外部にあるもののアドレスを保持することです (構造体の内部にはポインターが指す有効なものがないため)。

あなたが何を求めているのかは明らかではありません。文字列内の 4 バイトで表すことができる浮動小数点値の範囲は非常に限られています。バイナリ データ I/O を使用している場合は、ポインターとコンマを削除できます。

typedef struct
{
  char     command[14];
  float    pressure;
  float    temperature;
  uint32_t time_stamp;
}comStr;

コンマを表示したい場合は、もっと頑張る必要があります。

typedef struct
{
  char     command[14];
  char     pressure[4];
  char     comma1;
  char     temperature[4];
  char     comma2;
  char     time_stamp[4];
  char     CR;
} comStr;

データを慎重にロードする必要があります。

struct comStr com;
float         pressure = ...;
float         temperature = ...;
uint32_t      time_stamp = ...;

assert(sizeof(float) == 4);
...
memmove(&com.pressure, &pressure, sizeof(pressure));
memmove(&com.temperature, &temperature, sizeof(temperature));
memmove(&com.time_stamp, &time_stamp, sizeof(time_stamp));

同様の一連のメモリ コピーを使用して展開する必要があります。構造体では単純な文字列操作を使用できないことに注意してください。構造体のセクションとセクションのいずれかまたはすべてに 0 バイトが存在する可能性がありpressureます。temperaturetime_stamp


構造パディング

#include <stddef.h>
#include <stdio.h>
#include <stdint.h>

typedef struct
{
  char      command[14];
  float    *pressure;
  char      comma1;
  float    *temperature;
  char      comma2;
  uint32_t *time_stamp;
  char      CR;
} comStr;

int main(void)
{
    static const struct
    {
        char    *name;
        size_t   offset;
    } offsets[] =
    {
        { "command",     offsetof(comStr, command)     },
        { "pressure",    offsetof(comStr, pressure)    },
        { "comma1",      offsetof(comStr, comma1)      },
        { "temperature", offsetof(comStr, temperature) },
        { "comma2",      offsetof(comStr, comma2)      },
        { "time_stamp",  offsetof(comStr, time_stamp)  },
        { "CR",          offsetof(comStr, CR)          },
    };
    enum { NUM_OFFSETS = sizeof(offsets)/sizeof(offsets[0]) };

    printf("Size of comStr = %zu\n", sizeof(comStr));
    for (int i = 0; i < NUM_OFFSETS; i++)
        printf("%-12s  %2zu\n", offsets[i].name, offsets[i].offset);

    return 0;
}

Mac OS X での出力:

Size of comStr = 64
command        0
pressure      16
comma1        24
temperature   32
comma2        40
time_stamp    48
CR            56

64 ビット マシンでの構造体の大きさに注意してください。ポインターはそれぞれ 8 バイトで、8 バイトでアラインされています。

于 2013-04-14T04:08:29.167 に答える