我无法想到任何既不使用未定义行为,又不使用非常奇怪的结构来完成此操作的好方法。而且您希望使用不同类型的字段并不会使它变得更容易。
如果我想要编写这样的代码(其实我并不想),我可能会做类似以下的事情。
void *get_attr(struct Student *student, int field)
{
switch(field) {
case 0 : return (void*)&student->regNumber;
case 1 : return (void*)&student->fName;
case 2 : return (void*)&student->lName;
case 3 : return (void*)&student->email;
case 4 : return (void*)&student->phoneNumber;
case 5 : return (void*)&student->age;
}
return NULL;
}
然后你可以像这样使用它:
int main()
{
struct Student s = { "xxx333", "Jonny", "BGood", "my@email.com", 12345, 22 };
printf ("%s\n%s\n%s\n%s\n%d\n%d\n",
(char*)get_attr(&s, 0),
(char*)get_attr(&s, 1),
(char*)get_attr(&s, 2),
(char*)get_attr(&s, 3),
*(int*)get_attr(&s, 4),
*(short*)get_attr(&s, 5)
);
}
就我个人而言,我没有看到避免那些转换的好方法。一种方式是这样做,但不一定是好方法:
union attr_field {
char *c;
int *i;
short *s;
};
enum attr_type { CHAR, INT, SHORT };
struct attr {
union attr_field attr;
enum attr_type type;
};
struct attr get_attr2(struct Student *student, int field)
{
struct attr ret;
switch(field) {
case 0 : ret.attr.c = student->regNumber; ret.type = CHAR; break;
case 1 : ret.attr.c = student->fName; ret.type = CHAR; break;
case 2 : ret.attr.c = student->lName; ret.type = CHAR; break;
case 3 : ret.attr.c = student->email; ret.type = CHAR; break;
case 4 : ret.attr.i = &student->phoneNumber; ret.type = INT; break;
case 5 : ret.attr.s = &student->age; ret.type = SHORT; break;
}
return ret;
}
void print_attr(struct attr a)
{
switch(a.type) {
case CHAR: printf("%s\n", a.attr.c); break;
case INT: printf("%d\n", *a.attr.i); break;
case SHORT: printf("%d\n", *a.attr.s); break;
}
}
int main()
{
struct Student s = { "xxx333", "Jonny", "BGood", "my@email.com", 12345, 22 };
for(int i=0; i<6; i++) {
struct attr a = get_attr2(&s, i);
print_attr(a);
}
}
请注意,我有时会将结构体和指向结构体的指针作为函数参数使用。这种选择并没有特别的原因,只是碰巧就这样。你可以任选其一,它们都有各自的优缺点。如果性能是一个问题,我会选择指针。联合体也是同样的情况。我本可以选择字符数组并使用strncpy代替,对于int和short类型也可以跳过指针。在这里我的想法是,如果所有的联合成员都是指针,那么更清晰一些。但你需要自己对所有这些做出决定。如果你选择指针,可能明智的做法是在适当的地方使用const限定符。
如果你真的想这么做,我猜你可以像这样做:
void *attribs[6];
attribs[0] = (void*)s.regNumber;
printf("%s", (char*)attribs[0]);
这可以与上述提到的技术相结合。例如
struct attr attribs[6];
for(int i=0; i<6; i++)
attribs[i] = get_attr2(&s, i);
char
,但我想知道是否有其他的解决方法。 - Alexandros Voliotis