C 用零值而不是随机内存声明结构?
我有一个这样的结构:C 用零值而不是随机内存声明结构?,c,C,我有一个这样的结构: typedef struct string { unsigned long length; unsigned *data; } string; 我可以写点什么吗?这样当我这样做的时候: string s; length属性是零,而不是内存中发生的任何内容数据工作正常,因为它预设为零或空指针 现在发生的情况的示例: string s; printf("length: %lu\n", s.length); printf("pointer: %lu\n", (unsig
typedef struct string {
unsigned long length;
unsigned *data;
} string;
我可以写点什么吗?这样当我这样做的时候:
string s;
length
属性是零,而不是内存中发生的任何内容<代码>数据工作正常,因为它预设为零或空指针
现在发生的情况的示例:
string s;
printf("length: %lu\n", s.length);
printf("pointer: %lu\n", (unsigned long) s.data);
结果:
length: 140737488347584
pointer: 0
我不想为了将length
设置为零而对每个新字符串调用初始化函数
更多信息
现在我考虑一下,在我的特殊情况下,可能没有必要这样做(尽管这样做很好),因为大多数人最初会通过ctou
(从char-pointer导入UTF-8)设置字符串,并且该函数会将长度设置为零。您可以使用
string s = {0,NULL};
你可以用
string s = {0,NULL};
您可以使用宏“自动执行此操作”
您可以使用宏“自动执行此操作”来组合前面的两个答案(某种程度上),我会定义如下
#define STRING_INITIALIZER {0, NULL}
.
.
string s = STRING_INITIALIZER;
顺便说一句,您的struct
声明本身对于字符串来说看起来很奇怪。这不是我们在C语言中通常理解的字符串,而是一个动态的无符号数组,或者它实际上是一个字符串,然后它应该是char*
,为了结合前面的两个答案(某种程度上),我定义如下
#define STRING_INITIALIZER {0, NULL}
.
.
string s = STRING_INITIALIZER;
顺便说一句,您的struct
声明本身对于字符串来说看起来很奇怪。这不是我们在C语言中通常理解的字符串,而是一个动态的无符号数组,或者它实际上是一个字符串,然后它应该是char*
公认的答案回答了您提出的问题,但没有说明您是否应该这样做
字符串是一个类,具有类语义。对于每一条指令都有计数的内核代码,初始化器可能很好,但在应用程序代码中,静态初始化器丑陋且容易出错
可以用C编写类,stdio文件
类型是一个极好的例子,下面是应用于字符串类的相同想法:
typedef struct {
int length;
char *data;
} String;
String *sopen() {
String *s = malloc(sizeof(String));
if(s) {
s->length = 0;
s->data = NULL;
}
return s;
}
int sclose(String *s) {
free(s->data);
free(s);
return 0;
}
int main()
{
String *s = sopen();
return sclose(s);
}
出于隐喻的原因,我遵循了文件*
函数名样式。是的,还有更多的代码。是的,您必须显式地取消分配结构;但是请注意,即使您在代码示例中指望自动
类初始化,如果数据
曾经分配过,您也不能指望离开作用域为您自动解除分配存储
这种方法还有一个优点,就是从类的用户中抽象出数据的类型。由于对您真正想要使用的类型似乎有些困惑,这种灵活性可能会派上用场。公认的答案回答了您提出的问题,但没有说明您是否应该这样做
字符串是一个类,具有类语义。对于每一条指令都有计数的内核代码,初始化器可能很好,但在应用程序代码中,静态初始化器丑陋且容易出错
可以用C编写类,stdio文件
类型是一个极好的例子,下面是应用于字符串类的相同想法:
typedef struct {
int length;
char *data;
} String;
String *sopen() {
String *s = malloc(sizeof(String));
if(s) {
s->length = 0;
s->data = NULL;
}
return s;
}
int sclose(String *s) {
free(s->data);
free(s);
return 0;
}
int main()
{
String *s = sopen();
return sclose(s);
}
出于隐喻的原因,我遵循了文件*
函数名样式。是的,还有更多的代码。是的,您必须显式地取消分配结构;但是请注意,即使您在代码示例中指望自动
类初始化,如果数据
曾经分配过,您也不能指望离开作用域为您自动解除分配存储
这种方法还有一个优点,就是从类的用户中抽象出数据的类型。由于对您真正想要使用的类型似乎有些困惑,这种灵活性可能会派上用场。更好,但如果我可以在结构定义中设置一个选项来自动执行此操作,这将是最佳选择。对于可能使用此库的开发人员来说,每次都声明这样的新字符串可能没有那么好。{0}
比{0,NULL}
工作得更好。即使您更改了成员的实现和顺序,前一种方法仍然有效。如果您更改结构,后者会中断。更好的是,如果我可以在结构定义中设置一个选项来自动执行此操作,这将是最佳选择。对于可能使用此库的开发人员来说,每次都声明这样的新字符串可能没有那么好。{0}
比{0,NULL}
工作得更好。即使您更改了成员的实现和顺序,前一种方法仍然有效。如果您更改结构,后者将中断。这是一个Unicode结构,其中所有32位代码点全部存储在数据中。
@Delan:啊,我明白了。然后我会根据你的需要选择wchar\u t
,uint32\u t
或者uint32\u t
。为什么?在i386和amd64上,int
都是32位值。另外,我不想要wchar\u t
,因为这是一个16位的值。我刚刚在i686和x86\u 64上进行了测试,对我来说wchar\u t
在这两种情况下都是32位宽的。使用另一种类型而不是unsigned
更好地显示了您的意图,并明确了您的默认假设。但这是你的代码。愿便携性和健忘症之神咬你一口您应该对Unicode代码点使用uint32\u t
,以确保不会使类型超过需要的大小。更重要的是,你应该使用size\u t
而不是unsigned long
来表示长度。它是一个Unicode结构,所有32位代码点都完整地存储在数据中。@Delan:啊,我明白了。然后我会根据你的需要选择wchar\u t
,uint32\u t
或者uint32\u t
。为什么?在i386和amd64上,int
都是32位值。另外,我不想要wchar\u t
,因为这是一个16位的值