форсировать новое адресное пространство для функции (сделать статические переменные нестатическими) - PullRequest
0 голосов
/ 21 июля 2010

Я получил функцию в файле, которая работает для одного вызова функции. Но так как это зависит от множества статических объявлений в этом файле (я не создавал этот файл, и его слишком много для изменения). Он не будет работать с несколькими вызовами функций.

Есть ли способ сделать так, чтобы каждый вызов функции не знал о предыдущих или текущих вызовах? В результате создайте новое адресное пространство для каждого вызова функции.

как

//file inner.c
#include <stdio.h>

static int counter =1;

int incIt(int a){
  counter += a;
  return counter;
};

и основной файл

//file outer.c
#include <stdio.h>
#include "inner.h"

int main(){
  fprintf(stderr,"first: %d\n",incIt(5));
  fprintf(stderr,"second: %d\n",incIt(7));  //this should be independent of previous calls.
  return 0;
}

компилировать как

gcc -c inner.c
gcc outer.c

спасибо

Ответы [ 10 ]

3 голосов
/ 21 июля 2010

Если вы хотите, чтобы код повторно входил, вы должны избегать использования глобальных переменных или файловых статических переменных.

В C ++ вы оборачиваете переменные в классе (с помощью конструктора) и создаете экземпляр класса для каждого отдельного набора операций.

В C вы моделируете то, что делаете в C ++.

Например, в C ++:

#include <stdio.h>
class Counter
{
    int counter;
public:
    Counter() : counter(1) { }
    int incIt(int a) { counter += a; return counter; }
};

int main()
{
    Counter c1;
    Counter c2;
    printf("First: %d\n", c1.incIt(5));
    printf("Second: %d\n", c2.incIt(7));
    return 0;
}

Или, в C:

#include <stdio.h>
typedef struct Counter
{
    int counter;
} Counter;

void initCounter(Counter *c) { c->counter = 1; }
int incIt(Counter *c, int a) { c->counter += a; return c->counter; }


int main()
{
    Counter c1;
    Counter c2;
    initCounter(&c1);
    initCounter(&c2);
    printf("First: %d\n", incIt(&c1, 5));
    printf("Second: %d\n", incIt(&c2, 7));
    return 0;
}

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

3 голосов
/ 21 июля 2010

Это утверждение "Есть ли какой-нибудь способ, чтобы каждый вызов функции не знал о предыдущих вызовах или текущих вызовах?"Подразумевает, что это может работать для вас:

int incIt(int a){
  int localCounter = 1;
  localCounter += a;
  return localCounter;
};
3 голосов
/ 21 июля 2010

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

Объявляя вашу переменную static, вы движетесь в противоположном направлении - вы явно запрашиваете компилятор использовать ту же переменнуюв каждом звонке.Итак, решите, что именно вы пытаетесь сделать, а затем сделайте это.

Если вы не можете изменить объявления переменных и / или функций, то вам не повезло.Это не может быть сделано.

2 голосов
/ 21 июля 2010

Самое простое решение проблемы, которую вы представляете в коде, - это добавить новую функцию для обработки сброса счетчика.

Очевидно, что это мало что делает для повторного ввода кода, но может быть именно тем, что вам нужно, чтобы очистить историю прошлого.

2 голосов
/ 21 июля 2010

Формируйте новый дочерний процесс для каждого вызова.

0 голосов
/ 22 июля 2010

Предупреждение о гадком хаке: получить указатель на первый статический / глобальный в памяти и указатель на последний. Напишите функцию-обертку, которая копирует блок статики, чтобы каждый вызов получал свой собственный набор статик / глобалов. Это предполагает, что все интересные статические / глобальные переменные непрерывны в памяти ... Правильное решение - «изменить код, как описывает Джонатан Леффлер».

0 голосов
/ 21 июля 2010

С учетом данных требований я предлагаю это портативное решение. Решение будет имитировать локальные переменные. Замените все типы, встречающиеся в статических или глобальных переменных, на класс шаблона, экземпляр которого заменен типом. Шаблонный класс будет хранить стек заменяемого типа. Расставьте вещи так, чтобы вы могли выталкивать и извлекать этот стек из всех экземпляров этого шаблона с помощью одного вызова push или pop. При входе в унаследованную функцию нажмите, при выходе всплывающее окно.

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

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

0 голосов
/ 21 июля 2010

«Я бы хотел изменить мир, но они просто не дадут мне источники»

  #define static 

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

0 голосов
/ 21 июля 2010

Вот ответ, который я бы дал, если бы коллега спросил меня:

Не делай этого!

0 голосов
/ 21 июля 2010

Вы можете попробовать загрузить и выгрузить объект, скомпилированный из inner.c, с помощью dlopen.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...