2

構造を初期化するためにmallocを使用することは避け、オブジェクト指向スタイルを使用してCソフトウェアを設計するためのベストプラクティスを探しています(可能な場合)。

C ++ではなく、C99のみ

最初の質問、オブジェクトのような構造体を使用する場合、何が望ましいですか?そのポインタをtypedefするかどうか?

これらは私のテストです(すべてgccコンパイラを使用して動作します):

ケース1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct sItem{
    int n;
    char* text;
} oItem, *Item;

int main(int argc, char** argv) {
    Item i1=(&(oItem){.n=1, .text="A"});
    Item i2=(&(oItem){.n=100, .text="ABC"});
    printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 1, "A", 8
    printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 1, "ABC", 8
    return (EXIT_SUCCESS);
}

これは機能しますが、テキストが文字列を含むように初期化されていないため、機能しないはずです。これは無効なコードですか?

ケース2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct sItem{
    int n;
    char text[5];
} oItem, *Item;

int main(int argc, char** argv) {
    Item i1=(&(oItem){.n=1, .text="A"});
    Item i2=(&(oItem){.n=100, .text="ABC"});
    printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 1, "A", 12
    printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 1, "ABC", 12
    return (EXIT_SUCCESS);
}

これはうまくいき、正しいと思いますよね?

ケース3

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define Item_new(i, n, s) (&(oItem){0});Item_ctor(i, n, s);
#define Item_neww(i, x, s) (&(oItem){\
        .n=x,\
        .text=s\
})

typedef struct sItem{
    int n;
    char text[5];
} oItem, *Item;


void Item_ctor(Item i, int n, char* text){
    i->n=n;
    strcpy(i->text, text);
}

int main(int argc, char** argv) {
    Item i1=Item_new(i1, 10, "ABC");
    Item i2=Item_neww(i2, 10, "ABC");
    printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 10, "ABC", 12
    printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 10, "ABC", 12
    return (EXIT_SUCCESS);
}

これはとてもいいことだと思いますが、コードを隠していて、おそらく有害かもしれませんが、どう思いますか?私の場合3、最良の選択は何ですか:マクロまたはコンストラクター関数?

4

2 に答える 2

2

3をしないでください、保護されていないマクロを含むマクロは;私を非常に緊張させます。

代わりに、私はあなたの「新しい」と「ctor」を次のように置き換えます

#define Item_new(i, n, s) Item_ctor(&(oItem){0}, n, s)

Item Item_ctor(Item i, int n, char* text){
    if (i) {
      i->n=n;
      strncpy(i->text, text, 4);
    }
    return i;
}

Item_newこれは、値を返すマクロのような実際の関数に対するユーザーの期待を破ることはありません。

また、ctorは必要なチェックを実行し、メモリを上書きしないようにする必要があります。i->text[4]常に。になります0。(代わりにシンボリック定数5を使用して、呼び出しにも使用することをお勧めしstrncpyます。)

于 2012-08-19T23:54:26.560 に答える
1

ケース3は、私がほとんど見ているので、お勧めします。コンストラクター関数でコードをラップすることはまったく問題ありません-なぜコードを隠すことが問題になるのでしょうか?実際、これは機能です。実装からインターフェイスを非表示にします。また、そのためにマクロを使用しないでください。これは、マクロにとっては非常に複雑な作業ですが、それでも、マクロはしばしば悪です。

アプローチ1と2は非常に醜く(結局のところ、UBでもあります)、私の意見では読めません。さらに、ケース1はconstが正しくないため、代わりにケース2を使用するか(未定義の動作を呼び出すため、使用しないでください)、「text」をとして宣言しますconst char *

于 2012-08-19T23:03:47.133 に答える