C: сложное использование, объединение структур и объединений в качестве аргументов в функции, производящей неопределенное поведение - PullRequest
2 голосов
/ 08 декабря 2011

В настоящее время я пытаюсь разработать низкомасштабную программу для моделирования способа использования союзов в качестве аргументов, прежде чем разрабатывать крупномасштабную программу с использованием той же идеи. Союз состоит из двух структур.

В моей программе первая структура имеет unsigned int, а вторая структура имеет массив char из 81 элемента. У профсоюза, в дальнейшем, есть оба типа структур для членов. Далее идет прототип для функции ufuncx();, которая имеет два аргумента: указатель объединения и 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 ]

3 голосов
/ 08 декабря 2011

Если ваш компилятор не кричит на вас, вы либо не включили достаточное количество опций предупреждения, либо вам нужен лучший компилятор.Вы не можете передать (указатель на) член союза, как если бы он был частью союза;вам не разрешено обманывать, если вы не игнорируете предупреждения от вашего компилятора - что почти всегда является плохой идеей.

Обратите внимание, что ваши указатели a и b не инициализированы, поэтому их разыменование немедленно приводитк неопределенному поведению - дамп ядра, если вам повезет, и кто знает, что если вам не повезло.

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");
2 голосов
/ 08 декабря 2011

Для начала вы вызываете неопределенное поведение, используя неинициализированные a и b и не указывая им допустимые значения 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? */
0 голосов
/ 08 декабря 2011

В этом коде ваши переменные a и b никогда не указывают на действительный регион в памяти, как они должны. Это работает случайно в случае, который вы описали.

Вам следует установить a на адрес вашей переменной age, и не пытаться изменять a-> numtest, как вы делаете. То же самое для b-> note;

Другими словами, убедитесь, что у вас есть это в вашем коде:

a = &age;
b = &text;

Таким образом, a и b указывают на правильную и выделенную область памяти.

...