Как исправить выделенную память из взлома структуры другим методом?

Я разрабатываю драйвер на C для связи, и обмен сообщениями не имеет фиксированного размера. Рекомендация коммуникационной шины — использовать структуры для нескольких тем, что также относится и к моему случаю.

Моя 1-я проблема: я должен продолжать слушать новые сообщения, и когда я получаю одно, мне приходится обрабатывать данные сообщения (у него есть задержка) и все еще слушать новые сообщения.

1-е решение: использование потока при получении новых сообщений для обработки данных.

Моя вторая проблема: данные в сообщении могут иметь несколько данных структуры, и мой коммуникатор требует использования структуры для организации этих нескольких значений.

2-е решение: использование struct hack для выделения динамического размера памяти структуры.

Моя текущая проблема: когда я передаю свою структуру в качестве аргумента потоку или любой функции, я теряю структуру данных и получаю неправильные значения.

Короткий тест, который сделал:

typedef struct test{
    int size;
    int value[];
} test;

void allocation(test *v){
    test *aux = (test *)malloc(sizeof(test)+3*sizeof(int));
    int i;
    aux->value[0] = 2;
    aux->size = 3;
    aux->value[1] = 1;
    aux->value[2] = 5;
    printf("Teste1 %d\n",aux->size);
    for(i=0; i < aux->size; i++){
        printf("%d\n", aux->value[i]);
    }
    *v = *aux;
}

void cleanup(test *v){
    free(v);
}

int main(int argc, char *argv[]){
    test v;
    int i;

    allocation(&v);
    printf("Teste2 %d\n",v.size);
    for(i=0; i < v.size; i++){
        printf("%d\n", v.value[i]);
    }
    //cleanup(&v);
    return 0;
}

В этом тесте я получил правильные значения в первом отпечатке и неправильные значения во втором (только v.size дает правильное значение).

И моя структура немного сложнее, чем в тесте. Моя структура похожа на:

typedef struct test1{
    double v1;
    double v2;
} test1;

typedef struct test2{
    int size;
    test1 values[];
} test2;

Вы знаете, как исправить мою структуру памяти в этой функции, когда у меня есть все элементы, необходимые для исправления? Пожалуйста, имейте в виду, что желательно (не обязательно), чтобы я мог также выделить несколько test2 данных.


person Caio    schedule 20.01.2017    source источник
comment
Обратите внимание, что использование [] в конце структуры является гибким элементом массива (FAM) и полностью поддерживается в C99 и более поздних версиях. «Структурный хак» использует [1] вместо [] и не полностью поддерживается (хотя обычно он работает, не в последнюю очередь потому, что он был необходим до того, как были введены FAM, и по-прежнему необходим для сохранения обратной совместимости для рабочего кода).   -  person Jonathan Leffler    schedule 20.01.2017


Ответы (2)


Вы объявляете v не указателем, что означает, что память уже выделена для v, когда вы объявляете ее в main. Отправка ссылки на ваш allocation только правильно копирует size, поскольку он не выделяется динамически. Правильный способ сделать это:

  • Объявите свой v как указатель

  • Сделайте свой allocation возврат test* (test* allocation())

  • Назначьте его v в main. то есть что-то вроде v = allocate()

  • И с этого момента используйте v как указатель

EDIT: поскольку OP хочет, чтобы это работало только как аргументы, лучший способ сделать это - использовать двойной указатель. Проверьте следующий код:

typedef struct test{
    int size;
    int value[];
} test;

void allocation(test **v){
    test *aux = (test *)malloc(sizeof(test)+3*sizeof(int));
    int i;
    aux->value[0] = 2;
    aux->size = 3;
    aux->value[1] = 1;
    aux->value[2] = 5;
    printf("Teste1 %d\n",aux->size);
    for(i=0; i < aux->size; i++){
        printf("%d\n", aux->value[i]);
    }
    *v = aux;
}

void cleanup(test *v){
    free(v);
}

int main(int argc, char *argv[]){
    test **v;
    v = malloc (sizeof (test*));
    int i;

    allocation(v);
    printf("Teste2 %d\n",(*v)->size);
    for(i=0; i < (*v)->size; i++){
        printf("%d\n", (*v)->value[i]);
    }
    //cleanup(&v);
    return 0;
}

Обратите внимание, что ваша очистка тоже изменится после этого.

person 16tons    schedule 20.01.2017
comment
Ваш ответ действительно может исправить тест, но я не могу использовать его в потоке, после создания потока мы передаем функцию и адрес структуры в качестве аргументов, мне все еще нужно решить эту проблему с помощью аргументов. Вы знаете другое решение? - person Caio; 20.01.2017
comment
Да, вы можете использовать двойные указатели, посмотрите рабочий код в моем отредактированном ответе. Вам придется немного настроить его в соответствии с вашими настройками. - person 16tons; 20.01.2017

Дело в том, что вы назначаете структуры с неполным членом int value[]; Хотя в принципе нормально копировать две структуры по значению (и именно это и происходит, если вы пишете *v = *aux); Однако, поскольку компилятор не знает, какой размер члена value[] примет во время выполнения, "sizeof" v, а также размер *aux всегда равен 4, т. е. известный размер одного члена int size. Следовательно, копируется только это, тогда как массив value[] просто не копируется.

Выходом из этой ситуации может быть требование указателя на указатель (т.е. allocation(test **v), такой, чтобы зарезервированная память могла быть ему непосредственно назначена, используя указатель на struct test в main, т.е. test *vptr, и вызов allocation(&vptr).

Если вы не можете избежать передачи почтения к значению (вместо ссылки на указатель на значение), я полагаю, вам придется использовать memcpy для передачи содержимого. Но на самом деле это не имеет смысла, потому что тогда получатель должен заранее предоставить достаточно места для размещения массива value[] (что не так, если вы просто объявляете переменную вида test v). И тогда malloc и aux не имели бы смысла; вы можете напрямую писать в объект v, переданный по ссылке.

person Stephan Lechner    schedule 20.01.2017