Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-struct*在运行时强制转换?_C_C99 - Fatal编程技术网

C-struct*在运行时强制转换?

C-struct*在运行时强制转换?,c,c99,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;

假设我有以下代码:

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);
}

我是否可以避免代码重复并使用单个泛型函数?函数调用是在运行时决定的,因此宏是不相关的。函数之间的区别在于结构的名称,而不是它们的成员。

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

由于结构之间的公共结构构件的位置不一致,答案是否定的。因此,结构之间确实没有实际的共性。

使用这些结构,很难甚至不可能编写一个函数来处理它们。但是,如果您更改这些结构以共享另一个结构中的公共元素,那么这是可能的

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 structure的变量应该是每个struct的第一个成员,否则此技术将不起作用

现在声明一个函数,该函数的指针指向struct base

用途:

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);

有了这些结构,即使不是不可能,也很难编写一个单独的函数来处理它们。但是,如果您更改这些结构以共享另一个结构中的公共元素,那么这是可能的

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 structure的变量应该是每个struct的第一个成员,否则此技术将不起作用

现在声明一个函数,该函数的指针指向struct base

用途:

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);
我是否可以避免代码重复并使用单个泛型函数

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

函数调用将在运行时决定

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


函数之间的区别在于结构的名称,而不是它们的成员

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

因此,宏是不相关的

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

我是否可以避免代码重复并使用单个泛型函数

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

函数调用将在运行时决定

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


函数之间的区别在于结构的名称,而不是它们的成员

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

因此,宏是不相关的


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

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

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


如果要利用公共初始序列规则,则在使用具有-fno严格别名标志的编译器时,可能需要使用-fno严格别名标志,即使在不利用CI的情况下,使用该标志也可以提供针对编译器错误的保护。利用别名的代码应尽量使编译器明白,例如,通过确保适当的联合类型可见,但除非或直到编译器编写者开始注意这些事情,-fn不需要严格的别名来适应他们的失败。

在C89中,如果两个或多个结构以匹配类型的成员按匹配顺序开始,它们共享一个公共初始序列,并且都是同一个联合的一部分,则可以使用共享CI的任何类型的适当命名成员检查公共初始序列的任何部分。您的示例不使用匹配类型,因此不符合条件,但如果按照匹配顺序使用匹配类型,则符合条件。据我所知,20世纪90年代的C89编译器一致将相同的原则应用于指向结构的指针,因此,如果结构类型S1和S2具有CI,则可以使用任意一种类型的指针访问CI的成员。虽然该标准没有明确规定这种处理方式,但到目前为止,对于编译器来说,确保该规则适用于所有涉及联合的情况的最简单方法是使其也适用于所有带有指针的情况,许多人,包括标准的作者,都希望编译器自然会这样做,不管是否明确要求

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


如果要利用公共初始序列规则,则在使用具有-fno严格别名标志的编译器时,可能需要使用-fno严格别名标志,即使在不利用CI的情况下,使用该标志也可以提供针对编译器错误的保护。利用别名的代码应尽量使编译器明白,例如,确保适当的联合类型是可见的,但除非或直到编译器编写人员开始注意这些事情,-fn不需要严格的别名来适应他们的失败。

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

#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);

}

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

#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);

}

那太糟糕了,你排除了宏。这是这里最好的解决方案。@Jean-Françoisfare我排除了它们,因为我认为它们对运行时决策没有用处?函数之间的区别在于结构中成员的偏移量,因此somefunc2中的代码与somefunc1中的代码截然不同,而somefunc3中的代码又与其他两个函数截然不同。如果你真的想用一个函数来完成这三个函数的工作,你就必须利用宏的偏移量来编写代码,所涉及的数据结构将远远大于所示代码中微小的“重复”。那太糟糕了,你排除了宏。这是这里最好的解决方案。@Jean-Françoisfare我排除了它们,因为我认为它们对运行时决策没有用处?函数之间的区别在于结构中成员的偏移量,因此somefunc2中的代码与somefunc1中的代码截然不同,而somefunc3中的代码又与其他两个函数截然不同。如果你真的想要一个单一的功能来完成thr的工作
你必须编写代码,利用宏的偏移量,所涉及的数据结构将远远大于所示代码中的“重复”。在C和C++中,函数调用-控制路径-在编译时确定。没有运行时决策。C是这样的,但是C++中的虚函数是根据指针指向的对象的实际类型在运行时决定的。是的,但是在编译时确定基于该实际类型调用的函数。整个链接是由编译器构建的,没有运行时支持。动态外观是为了程序员的利益而形成的一种假象,在征得程序员的同意后,将许多损坏的名称隐藏在一个名称后面,并根据参数类型进行分派。与Lisp、Smalltalk和Python等语言非常不同,它们可以在程序控制下更改名称绑定。我说的是函数重写——派生类重写基类中定义的虚拟函数——而不是函数重载。如果通过基类指针调用虚拟函数,则在运行时确定要调用的实际函数。编译器无法知道指针在编译时指向什么对象。这是一个常见的误解。如何在运行时确定?不管是否为虚拟函数,编译器永远不知道将传递什么数据。编译器创建控制将流经的路径。根据名称和参数类型调用重载函数。基于名称和。。。参数类型!没有什么不同,除了Koenig查找被加入到混合中。更多机械,但静态确定。100%的逻辑是二进制的:没有库支持,没有解释器。没有运行时。在C和C++中,函数调用-控制路径-在编译时确定。没有运行时决策。C是这样的,但是C++中的虚函数是根据指针指向的对象的实际类型在运行时决定的。是的,但是在编译时确定基于该实际类型调用的函数。整个链接是由编译器构建的,没有运行时支持。动态外观是为了程序员的利益而形成的一种假象,在征得程序员的同意后,将许多损坏的名称隐藏在一个名称后面,并根据参数类型进行分派。与Lisp、Smalltalk和Python等语言非常不同,它们可以在程序控制下更改名称绑定。我说的是函数重写——派生类重写基类中定义的虚拟函数——而不是函数重载。如果通过基类指针调用虚拟函数,则在运行时确定要调用的实际函数。编译器无法知道指针在编译时指向什么对象。这是一个常见的误解。如何在运行时确定?不管是否为虚拟函数,编译器永远不知道将传递什么数据。编译器创建控制将流经的路径。根据名称和参数类型调用重载函数。基于名称和。。。参数类型!没有什么不同,除了Koenig查找被加入到混合中。更多机械,但静态确定。100%的逻辑是二进制的:没有库支持,没有解释器。无运行时。结构基类型浪费三个字节的浪费,在许多情况下可以通过先使用指针,然后是int,然后是char来避免,如果结构的变量部分包含任何8位或16位类型的字段或数组,则可以利用公共初始序列规则,可以放置它们来填充第一个字节为common的单词2。struct base type浪费三个字节,这在许多情况下可以通过先使用指针,然后使用int,然后使用char,然后利用公共初始序列规则,如果结构的可变部分包含任何8位或16位类型的字段或数组,则可以将这些字段或数组放置以填充第一个字节为common2的单词。你不是说-函数调用将在运行时决定吗?这是如何让您在运行时做出决定的?这不是检查开关盒内的用户输入并决定调用哪个函数@ARMY007您不是说过-函数调用将在运行时决定吗?这是如何让您在运行时做出决定的?这不是检查开关盒内的用户输入并决定调用哪个函数@陆军007