C:结构和联合的复杂使用。联合作为函数中的参数产生未定义的行为

时间:2011-12-08 01:47:14

标签: c function pointers struct unions

我目前正在尝试开发一个低规模程序来模拟使用联合作为参数的方法,然后使用相同的想法开发更大规模的程序。联盟由两个结构组成。

在我的程序中,第一个struct有一个unsigned int,第二个struct有81个元素的char数组。在下文中,联合体具有两种类型的成员结构。接下来是函数ufuncx();的原型,它有两个参数,一个是union指针和一个int。

我正在尝试实现一个方法,我可以将其传递给一个函数,一个联合指针,指向联合外部定义的两个结构地址之一,它们也是联合结构成员的一部分。

源代码列表:

/*
   this is a program test to see if different types of union members can `enter code as
   function arguments of the same union type.
*/

#include <stdio.h>
#include <string.h>

struct id_num
{
   unsigned short int idnumber;
};

struct namedisc
{
   char name[81];
};

union combo_x
{
   struct id_num numtest;
   struct namedisc note;
};

int ufuncx(union combo_x *, int);

int main(void)
{

//step 1:

    union combo_x *a, *b;

    //struct data

    struct namedisc text;
    struct id_num age;

//step 2a:

    //pointer *a - uses the id_num struct

    age.idnumber = 25;
    a->numtest = age;

//step 2b:

    //pointer *b - uses the namedisc struct

    strcpy(text.name,"John Doe\0");
    b->note = text;

//step 3:

      /*=- if you comment this, a pointer error in run time occurs -=*/
      printf(".... %s\n",b->note.name);

//step 4:

    //show output

    ufuncx(a,1);
    ufuncx(b,2);

    return 0;
}

int ufuncx(union combo_x *data,int part)
{

    if(part < 1 || part > 2)
    {
        printf("we dont have that part...\n");
        return -1;
    }

    if(part == 1)
    {
        printf(" age = %d ",data->numtest.idnumber);
    }

    if(part == 2)
    {
        printf("name = %s ",data->note.name);
    }

    printf("(it works!)\n");

    return 0;
}

这是源代码的运行时输出:

.... John Doe
 age = 25 (it works!) 
name = John Doe (it works!)

这看起来不错,似乎有用,但是有问题。 在我的程序的第3步中,如果我注释掉printf();语句,我得到:

 age = 25 (it works!)
name = (null) (it works!)
!$h *tl J#@^&

name = (null)(它有效!),在此更改后面跟随随机垃圾,表示错误的指针地址。

注释掉的printf();语句在运行时不应该有所不同,但在这种情况下确实如此。我的第一个想法是,我有一个指针问题,特别是当我尝试使用间接运算符将结构文本的地址分配给指针b时。

我不认为在步骤2b中出了什么问题。我试过用几种方法重新编写它,但是我遇到了编译器错误。这是我被困的地方 - 因为我遇到了逻辑错误。

基于这个程序思想的大规模模型将有两个由许多结构组成的联合作为成员,因为每个结构将有许多不同数据类型的成员(即短整数,字符数组等)将被传递作为函数的参数。同样的目标,只是扩大了。

提前致谢。

3 个答案:

答案 0 :(得分:3)

如果你的编译器没有尖叫你,你要么没有打开足够的警告选项,要么你需要一个更好的编译器。你不能传递(一个指针)一个联盟成员,就好像它是一个联盟的一部分;除非你忽略了编译器的警告,否则不允许作弊 - 这几乎总是一个坏主意。

请注意,您的指针ab未初始化,因此立即取消引用它们会导致未定义的行为 - 如果您幸运的话,核心转储,以及谁知道如果您不幸的话。< / p>

union combo_x *a, *b;
struct namedisc text;
struct id_num age;

age.idnumber = 25;
a->numtest = age;   // a is uninitialized - undefined behaviour

strcpy(text.name,"John Doe\0");
b->note = text;     // b is uninitialized - undefined behaviour

您可能会想到:

struct namedisc text;
struct id_num age;   
union combo_x *a = (union combo_x *)&text;
union combo_x *b = (union combo_x *)&age;

a->numtest.idnumber = age;
strcpy(b->note.name, "John Doe");

但是演员是关闭编译器合理投诉的必要条件。

你可以合法地做的是:

union combo_x a;
union combo_x b;

a.numtest.idnumber = age;
strcpy(b.note.name, "John Doe");

答案 1 :(得分:2)

首先,您使用ab未初始化并且未将其指向任何有效的union combo_x(通过malloc或者union combo_x来导致未定义的行为将它们指向现有union combo_x *a, *b; struct namedisc text; struct id_num age; age.idnumber = 25; a->numtest = age; /* dereferencing a...where is a pointing? */ 的地址。如果您的编译器没有告诉您,请打开警告。请参阅:

{{1}}

答案 2 :(得分:0)

在此代码中,您的变量ab永远不会指向内存中的有效区域。在您描述的情况下,它正在偶然地发挥作用。

您应该将a设置为age变量的地址,而不是尝试修改a-&gt; numtest。对于b-> note;

也是如此

换句话说,你可以在代码中使用shure:

a = &age;
b = &text;

这样,ab都指向有效且已分配的内存区域。