C - struct *在运行时播放?

时间:2017-02-04 18:42:34

标签: c c99

假设我有以下代码:

struct str1
{
    int common1;
    char common2;
    char *common3;
    long int aaaaaaaa;
}

struct str2
{
    char bbbb;
    char *common3;
    int common1;
    char common2;
}

struct str3
{
    char ccccccccc[200];
    int common1;
    char common2;
    int dddddddd;
    int eeeeeeee;
    char *common3;
}

void somefunc1(struct str1 var)
{
    printf("%d %c %s", var.common1, var.common2, var.common3);
}

void somefunc2(struct str2 var)
{
    printf("%d %c %s", var.common1, var.common2, var.common3);
}

void somefunc3(struct str3 var)
{
    printf("%d %c %s", var.common1, var.common2, var.common3);
}

我可以以某种方式避免代码重复并使用单个通用函数吗?函数调用将在运行时决定,因此宏是无关紧要的。函数之间的所有区别都是结构的名称,而不是它们的成员。

5 个答案:

答案 0 :(得分:4)

由于“共同”结构成员的位置在结构之间不一致,答案是否定的。因此,结构之间实际上没有实际的共性。

答案 1 :(得分:3)

使用这些结构很难(如果不是不可能)编写一个能够处理它们的单个函数。但是,如果您更改这些结构以从另一个结构共享这些共同元素,那么它将是可能的。

struct base
{
    int common1;
    char common2;
    char *common3;
};

struct str1
{
    struct base b;
    long int aaaaaaaa;
};

struct str2
{
    struct base b;
    char bbbb;
};

struct str3
{
    struct base b;
    char ccccccccc[200];
    int dddddddd;
    int eeeeeeee;
};

注意:struct base结构的变量应该是每个struct的第一个成员,否则这种技术将不起作用。

现在声明一个指向struct base的函数。

void somefunc(struct base* var)
{
    printf("%d %c %s\n", var->common1, var->common2, var->common3);
}

用途:

struct str1 s1 = { 1, 'a', "sfad"};
struct str2 s2 = { 2, 'b', "sdfazx"};
struct str3 s3 = { 3, 'c', "oiurotu"};

somefunc((struct base*) &s1);
somefunc((struct base*) &s2);
somefunc((struct base*) &s3);

答案 2 :(得分:0)

  

我可以以某种方式避免代码重复并使用单个通用函数吗?

没有。这听起来类似于C ++模板,当然C没有并且没有模拟,除非你包含预处理器。 C11有_Generic,但这会产生一种函数重载:每种类型一个函数,预处理器支持通过单个名称调用它们。

  

函数调用将在运行时决定

在C和C ++中,函数调用 - 控制路径 - 在编译时确定。没有运行时“决定”。

  

函数之间的所有区别都是结构的名称,而不是它们的成员。

实际上,每个结构的布局都有一个关键区别。名称位于不同的位置。 C编译器将名称转换为位置。编译后,没有名称和类型,没有任何内容表明某个位置被命名为common1或是结构的一部分。只有对内存位置的引用。您可以正确使用该语言,以确保引用到您想要的位置。

  因此,宏是无关紧要的。

预处理器允许您在编译器将名称转换为数字之前操作名称。如果你想用C“按名字”做任何事情,一个宏是镇上唯一的游戏。

答案 3 :(得分:0)

在C89中,如果两个或多个结构以匹配顺序的匹配类型的成员开始(它们共享公共初始序列)并且两者都是同一联合的一部分,则可以使用适当的部分检查公共初始序列的任何部分。共享CIS的任何类型的命名成员。您的示例不使用匹配类型,因此它不符合条件,但如果它在匹配顺序中使用匹配类型,则会。据我所知,C89编译器在20世纪90年代一致地使用了与结构指针相同的原理(因此,如果结构类型S1和S2具有CIS,则可以使用任一类型的指针来访问CIS的成员)。虽然标准没有明确规定这种处理方式,但迄今为止编制者确保该规则适用于所有涉及工会的案例的最简单方法是使其适用于所有情况下的指针以及许多人(可能包括标准的作者在内,预计无论是否明确要求,编译器都会自然地这样做。

C99要求如果代码要使用一种结构类型的指针 访问另一个CIS的成员时,必须可以看到union类型的完整定义,以便让编译器知道类型之间可能存在的别名。不幸的是,虽然这个规则有一个明确而明显的目的(允许程序员利用CIS规则,同时允许编译器假设访问完全不相关的结构不会别名),但某些编译器编写者会假设不使用结构类型的指针访问任何其他,即使包含两种类型的完整联合类型声明是可见的,甚至在结构实际上是同一联合对象的成员的情况下。

如果要利用Common Initial Sequence规则,可能需要在使用具有一个的编译器时使用-fno-strict-aliasing标志(即使不利用CIS,使用该标志可以提供针对编译器错误的保护)。利用别名的代码应该努力使编译器显而易见(例如,通过确保合适的联合类型是可见的)但除非或直到编译器编写者开始关注这些事情,否则-fno-strict-aliasing将是必要的以适应他们的失败这样做。

答案 4 :(得分:0)

看起来我对限制预处理器的使用是错误的:

#include <stdio.h>

struct str1
{
    int common1;
    char common2;
    char *common3;
    long int aaaaaaaa;
};

struct str2
{
    char bbbb;
    char *common3;
    int common1;
    char common2;
};

struct str3
{
    char ccccccccc[200];
    int common1;
    char common2;
    int dddddddd;
    int eeeeeeee;
    char *common3;
};

#define somefunc(var) \
    printf("%d %c %s\n", var.common1, var.common2, var.common3);

int main()
{
    struct str1 var1 = {1,'a',NULL, 4};
    struct str2 var2 = {'b',NULL,2,'b'};
    struct str3 var3;
    var3.common1 = 3;
    var3.common2 = 'c';
    var3.common3 = NULL;


    somefunc(var1);
    somefunc(var2);
    somefunc(var3);

}

输出:

1 a (null)
2 b (null)
3 c (null)