Я не эксперт C. Я не делал никаких C с моего CS1 & 2 дня в колледже. Я сделал немного C++ здесь и там, но это было давно. Так что я спрашиваю о правильном шаблоне, чтобы решить проблему, которую я воспринимаю.Абстракции уровня экземпляра в C
Я решил заняться довольно амбициозной задачей, и я делаю это в C. Одна из вещей, которые я изучаю (пере), - это разные методы абстракции в C по сравнению с теми, которые я привык иметь в высших уровня. Проблема, с которой я сталкиваюсь, и спрашиваю, в частности, имеет отношение к тестированию и функциям.
Например, у меня есть две функции: f
и g
и f
будут звонить по номеру g
, если выполняются определенные условия.
void f(object* obj) {
// ...
if(obj->state)
g(obj);
// ...
}
Мне нужно, чтобы проверить, что на самом деле g
называют, но я также не хочу, чтобы на самом деле выполнить его, так как он может делать все виды других вещей. Обычно это будет решаться на языке более высокого уровня посредством интерфейсов или абстрактных классов или наследования. Но в C у меня нет этих методов.
Фактически единственным решением этой проблемы, о котором я могу думать, является использование указателей функций. Вместо того, чтобы напрямую звонить g
, я должен добавить указатель на object
так, чтобы он имел указатель на g
, который я могу заменить указателем на другую функцию в тестах.
typedef struct object {
int state;
void (*g)(object* obj);
} object;
void f(object* obj) {
// ...
if(obj->state)
obj->g(obj);
// ...
}
Тогда обычно я просто указать на g
при выделении экземпляра g
но в моем тесте я указываю obj-> г на другую функцию, тот, который просто проверяет входящие значения, и отмечает, что это было на самом деле называется.
Это идея, которую я имею прямо сейчас, но я не уверен, что это вполне правильный C-ish способ решить эту проблему. Надеюсь, мое описание иллюстрирует проблему, с которой я сталкиваюсь, но то, что мне действительно интересно, - это то, как лучше справиться с этим.
Каковы рекомендуемые шаблоны проектирования для решения этой проблемы в C?
Что вы имеете в виду, когда говорите, что вам нужно проверить, что g вызывается, но вы не хотите его выполнять? Вы имеете в виду, что иногда вы собираетесь работать в каком-то тестовом режиме, а затем вы хотите запустить альтернативную версию g? – David
да точно. Реальный g может быть довольно сложным, и то, что он делает, не имеет особого значения для целей тестирования f. Я не хочу запускать все, что есть в g, только для проверки f. Вы бы использовали интерфейсы и stubbing, если вы собираетесь решить это на C#, например. –
В итоге я фактически не делал ни одного из приведенных ниже ответов. Вместо этого я создал пользовательский malloc, который затем вставляю небольшой заголовок в каждое распределение памяти (только в отладочном), которое включает в себя «нужный» номер перечисления. Затем я создал новую структуру, которая имеет ту же структуру плюс желаемое значение хэш-функции. Когда в режиме отладки я смотрю на заголовок, обнаруживаю, какая структура входит, и либо делает хеш, как обычно, либо просто использует предоставленный хеш, если он существует. Работает как шарм и не имеет эффектов исполнения в выпуске! –