0

2 つの「モジュール」があるとします。たとえば、RS-232 ポートのハードウェア インターフェイス レイヤーと、それをより抽象化するためのその上のレイヤー。

次のような受信バッファがありますU8BIT myBuffer[MAX]U8BIT型定義されています:typedef unsigned char

ただし、受信できるメッセージには 2 種類あります。1 つはヘッダーがあり、もう 1 つはヘッダーがありません。このロジックはすでに書かれています。

「上のレイヤー」はこのバッファーにアクセスしますが、これがヘッダーまたはヘッダーなしのメッセージであるかどうかを認識していません。

したがって、次のような関数があります。

U8BIT * fooBuffer(U8BIT * maxLength)
{
    U8BIT * retval;
    if( isHeaderless() )
    {
        retval = &(myBuffer[0]);
        *maxLength = MAX;
    }
    else
    {
        retval = &(myBuffer[5]);
        *maxLength = MAX - 5;
    }
    return retval;
}

この関数を呼び出す関数が、返されたポインタの内容を変更できないようにするにはどうすればよいですか?

はい、私はそれが常に可能であることを知っています。そして、他の人がそれを変更しようとするのを難しくしようとしないでください. を変更しようとするとコンパイラが文句を言うので、間違いを犯しにくくなるように「不可能」にしたいのですconst

次のように関数を宣言できますか。const U8BIT * fooBuffer(U8BIT * maxLength)

4

4 に答える 4

1

私自身の経験則は、関数からポインターを返したいという衝動を感じるときはいつでも、それを私のプログラム設計が悪いことを示す大きな赤い旗と見なします。constポインターを返すことは、おそらくその規則のまれな例外ですが。

あなたの場合、コードはおそらく再設計の恩恵を受けるでしょう。これが私の提案です。

#define FIRST_INDEX       0u
#define SOME_OTHER_INDEX  5u
#define N                 SOMETHING

static const uint8_t MAX = something;
static uint8_t myBuffer [N];


uint8_t fooBuffer (const uint8_t* retVal)
{
    uint8_t maxLength;

    if( isHeaderless() )
    {
        retval = &myBuffer[FIRST_INDEX];
        maxLength = MAX;
    }
    else
    {
        retval = &myBuffer[SOME_OTHER_INDEX];
        maxLength = (uint8_t) (MAX - SOME_OTHER_INDEX);
    }

    return maxLength;
}

プログラム設計の変更:

  • myBufferが、コードモジュールの外部からアクセスまたは変更できないプライベート変数であることを確認しました。
  • ポインタの代わりに値でmaxLengthを返しました。なぜポインタを介して返す必要があるのか​​わかりません。
  • retValはconstポインタを介して返されます。

コーディングスタイルの変更:

  • U8BITタイプを削除し、C99/C11互換のuint8_tに置き換えました。C99 / C11コンパイラがない場合は、typedef unsigned char uint8_tどこかにあります。これにより、他のプログラマーがコードを読みやすくなります。あなたがあなた自身の特別なタイプを使うならば、彼らはその特定のタイプについて何か魔法があると誤って疑うようになるかもしれません。
  • &myBuffer []の周りのあいまいな括弧は、目的を満たさなかったため削除しました。
  • マジックナンバーを削除しました。

MISRA-C:2004準拠:(このMISRAにタグを付けたため)

  • uすべての整数定数リテラルには接尾辞が必要です。
  • -演算子の結果を基になる型uint8_tに型キャストする必要があります。
于 2012-07-04T09:52:09.560 に答える
1

この関数を呼び出す関数が、返されたポインタの内容を変更できないようにするにはどうすればよいですか?

constコードのユーザーに意図を示すポインターを返します。
ただし、変更できないという保証はありません。それらが可能であることを覚えておいてください。もしそうなら、それはUndefined Behaviorになります。

正しいセマンティクスに従うことしかできず、誰かがポインター ハッカーを悪用してコードを壊さないことを願っています。コードにアクセスできる限り、コードを破ることは常に可能です。したがって、できることは、意図を明確に表現することだけです。

于 2012-06-28T13:15:27.107 に答える
1

const U8BIT *関数の戻り値の型として使用します。

たとえば、関数で:

const U8BIT * fooBuffer(U8BIT * maxLength)
{
    U8BIT * retval;  

    // code

    return (const U8BIT *) retval;
} 

retvalポインターがfooBuffer関数内で逆参照されていない場合は、それを としても宣言すると、const U8BIT *return ステートメントでのキャストは不要になります。

于 2012-06-28T13:15:44.657 に答える
0

はい、すでにconst修飾された戻り値の使用を開始しています。

しかし、それ以上に、実際には変更できない場所に値を返すことができます。私が正しく見れば、可能な戻り値は2つしかありません:

... myBuffer... // supposing that this is known at compile time

static U8BIT const retval0 = &(myBuffer[0]);
static U8BIT const retval1 = &(myBuffer[5]);

U8BIT const* fooBuffer(U8BIT * maxLength)
{
    if(isHeaderless()) return &retval0;
    else return &retval1;
}

プラットフォームには、2 つretvalが読み取り専用セクションになるようにする手段さえある場合があります。

于 2012-06-28T13:46:27.187 に答える