C、 不使用malloc初始化结构
我将避免使用malloc来初始化结构,我正在寻找使用oo风格(如果可能)设计C软件的最佳实践 只有C99,而不是C++ 第一个问题,当像对象一样使用结构时,什么更可取?是否键入其指针 以下是我的测试(所有工作都使用gcc编译器): 案例1C、 不使用malloc初始化结构,c,oop,constructor,struct,C,Oop,Constructor,Struct,我将避免使用malloc来初始化结构,我正在寻找使用oo风格(如果可能)设计C软件的最佳实践 只有C99,而不是C++ 第一个问题,当像对象一样使用结构时,什么更可取?是否键入其指针 以下是我的测试(所有工作都使用gcc编译器): 案例1 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct sItem{ int n; char* text; } o
#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);
}
#包括
#包括
#包括
类型定义结构站点{
int n;
字符*文本;
}oItem,*项目;
int main(int argc,字符**argv){
项目i1=(&(oItem){.n=1.text=“A”});
项目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
返回(退出成功);
}
这是可行的,但我认为不应该,因为文本没有初始化为包含字符串。
这是一段无效的代码吗
案例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);
}
#包括
#包括
#包括
类型定义结构站点{
int n;
字符文本[5];
}oItem,*项目;
int main(int argc,字符**argv){
项目i1=(&(oItem){.n=1.text=“A”});
项目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
返回(退出成功);
}
这是可行的,我认为这是正确的,是吗
案例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);
}
#包括
#包括
#包括
#定义新的(i,n,s)(&(oItem){0});项目(i,n,s);;
#定义新项目(i、x、s)(&(oItem){\
.n=x\
.text=s\
})
类型定义结构站点{
int n;
字符文本[5];
}oItem,*项目;
无效项目(项目i、整数n、字符*文本){
i->n=n;
strcpy(i->text,text);
}
int main(int argc,字符**argv){
第i1项=新项目(第i1、10、ABC);
i2项=新项目(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
返回(退出成功);
}
我认为这很好,但是隐藏了代码,可能是有害的,你认为呢?
在案例3中,最好的选择是什么:宏还是构造函数?案例3是我经常看到并推荐的。将代码包装在构造函数中是非常好的-为什么隐藏代码会成为一个问题?事实上,这是一个特性——从实现中隐藏接口。此外,不要为此使用宏——这对于宏来说太复杂了,尽管如此,宏通常是邪恶的
在我看来,方法1和2非常难看(事实证明,它们也是UB)并且不可读。此外,案例1不是常量正确的,或者使用案例2(因为它调用了未定义的行为,所以不要使用它),或者将“text”声明为
const char*
不做3,即包含未受保护的的宏代码>让我非常紧张
相反,我将用以下内容替换您的“new”和“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\u new
的期望:一个真正的
类似于返回值的宏的函数
ctor应该进行必要的检查,并且永远不要覆盖内存,i->text[4]
将始终是0
。(最好使用符号常量而不是5
,并将其用于strncpy
调用。)示例1和2不是有效代码。您不能接受临时文件的地址并期望它包含有效值。如果需要堆栈分配的指针,请使用alloca。2是有效的,为什么说它不是有效的?因为您使用的是临时值的地址,这是未定义的行为。在案例2中,我不使用临时值的地址…我不会使用不反映它是指针的名称来定义指针。如果Item_ptr太长,我只会使用Item*。谢谢,在案例3中,使用宏是一种更有效的初始化结构的方法,因为我使用literal struct复合初始化,使用ctor我必须首先将所有结构数据初始化为0(使用{0}),然后设置它们,这是真的吗?感谢again@blow它不是效率最低,就是缺陷很小,不值得编写和维护这样一个宏。在一个性能差、内存非常少的嵌入式设备中,您会选择哪一种?好的,谢谢,我会按照您建议的方向来做,但我对我要做的事情有些怀疑,我认为我选择OO这样的设计模式是错误的,但为此,我可能会打开一个新的线程。再次感谢。@H2C03在示例3中,main中的两个指针指向的数据驻留在哪里?