C结构体作为一种数据类型

20

我希望能够像这样做:

typedef struct
{
    char* c_str;

} string;

string s = "hello";

有什么办法可以做到吗?

我知道可以做到这一点:

typedef struct
{
    char* c_str;

} string;

string s = { "hello" };

但是当只有一个成员变量时,我不喜欢使用大括号。

4个回答

31

你可以使用 typedef 代替 struct

typedef char* string;
string s = "hello";

但是const string会使得指针成为常量,而不是指向的数据。因此,const string s等价于char* const s。一种解决方法是为常量字符串定义另一种类型:

typedef char* string;
typedef const char* const_string;

对于原始结构体,同样适用这个问题。(C++也有同样的“问题”,这就是为什么它在其容器类型中使用iteratorconst_iterator的原因。)

对于指针类型的typedef的优点是可以缩短类型的长度。

string s1, s2, s3;

而不是

char *s1, *s2, *s3;

9
值得一提的是,使用typedef定义指针时,众所周知的一个问题是,const被应用于指针而不是指向的数据。换句话说,const string s将等同于char* const s而不是你通常期望的const char* s - barak manos
typedef 的另一个问题是它创建的是类型的别名而不是新类型。结果是编译器进行的类型检查与 C++ 中所期望的不同。因此,对 char * 进行 typedef 将与任何其他 char * 一样,就编译器而言。如果问题是通过使用 struct 提供更具体的类型检查方式,则使用 typedef 将无法提供编译器类型检查。 - Richard Chambers

14

在 C 中无法实现,但如果您添加一个接受一个适当参数的构造函数,则可以在 C++ 中完成。编译器将完成其余工作。如果想要避免隐式转换行为,可以将构造函数标记为显式(explicit)。

C++ 中:

struct string {

    char * m_c_str;

    /* explicit */ string(char* c_str) : m_c_str(c_str) { }
};

int main(int argc, char * argv[]) {

    string s = "hello";

    return 0;

}

4
有没有任何方式可以做到这一点呢?
不可能使用structunion来实现。第6.7.9节的第16段规定:
[...]具有聚合类型或联合类型的对象的初始化程序必须是元素或命名成员的大括号括起来的初始化程序列表。
可以通过其他数据类型的方式来实现相同的效果,如在这个答案中所解释的那样。

3

不确定这是否符合C标准,并且由于微软Visual Studio在解释标准方面有些灵活,因此这里提供的方法可以实现编译和查看Visual Studio 2005调试器中的工作。

虽然如果您不喜欢花括号初始化程序,则可能也不会喜欢宏。

typedef struct {
    char *c_str;
} String;

// following macro assigns the string to the struct member and uses the
// comma operator to make the statement return the original struct variable.
#define xString(x, y) ((x).c_str = (y), (x))

void jjj (void)
{
    String b = xString(b,"hello");

}

我能同时定义多个变量,所以多个变量定义可以在同一行上编译,例如:
String b = xString(b,"hello"), c = xString(c,"Jello");

也许您想要一个宏,可以用一种函数式语言的构造完成整个语句,尽管每个语句只能有一个这样的宏,所以在同一行上使用多个需要使用分号将其分隔成单个定义语句。

#define xString(x,y) String x = (x.c_str = (y), x)

它将被用作

void jjj (void)
{
    xString(myStruct, "hello");
    int  j = 2;

    //  .. do stuff
}

或者你可以直接使用

#define xString(x,y) String x = {y}

如果你希望在某些情况下对特定类型的char *进行编译时参数检查,那么初始化列表似乎确实是最好的方法。

当你像下面这样使用初始化列表在定义结构体变量的同时初始化多个结构体成员时,就会让人感到非常棒。

typedef struct {
    int len;
    char *c_str;
} String2;

#define yString(x,y) x = (x.c_str = (y), x.len = strlen(y), x)

void jjj (void)
{

    String2 b2 = yString(b2,"Hello");
    int  j = 2;

    //  .. do stuff
}

出于好奇,我尝试了另一种变体,如下所示。这更多地涉及到遵循这种方法的可能性,而不是具体的问题。使用相同的struct,但使用不同的宏来指定要初始化的struct成员以及其值。

typedef struct {
    int len;
    char *c_str;
} String2;

#define zString(x,y,a,b) x=(x.c_str=(y),x.a=(b),x)

void jjj (void)
{
    String2 b3 = zString(b3,"Hello",len,72);

    //  ... do stuff
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接