. Они очень удобны в использовании, когда вам нужны разные функции в разное время или на разных этапах разработки. Например, я разрабатываю приложение на главном компьютере с консолью, но окончательная версия программного обеспечения будет размещена на Avnet ZedBoard (у которого есть порты для дисплеев и консолей, но они не нужны / не нужны для Окончательный релиз). Поэтому во время разработки я буду использовать printf
для просмотра сообщений о состоянии и ошибках, но когда я закончил, я не хочу ничего печатать. Вот что я сделал:
// First, undefine all macros associated with version.h
#undef DEBUG_VERSION
#undef RELEASE_VERSION
#undef INVALID_VERSION
// Define which version we want to use
#define DEBUG_VERSION // The current version
// #define RELEASE_VERSION // To be uncommented when finished debugging
#ifndef __VERSION_H_ /* prevent circular inclusions */
#define __VERSION_H_ /* by using protection macros */
void board_init();
void noprintf(const char *c, ...); // mimic the printf prototype
#endif
// Mimics the printf function prototype. This is what I'll actually
// use to print stuff to the screen
void (* zprintf)(const char*, ...);
// If debug version, use printf
#ifdef DEBUG_VERSION
#include <stdio.h>
#endif
// If both debug and release version, error
#ifdef DEBUG_VERSION
#ifdef RELEASE_VERSION
#define INVALID_VERSION
#endif
#endif
// If neither debug or release version, error
#ifndef DEBUG_VERSION
#ifndef RELEASE_VERSION
#define INVALID_VERSION
#endif
#endif
#ifdef INVALID_VERSION
// Won't allow compilation without a valid version define
#error "Invalid version definition"
#endif
В version.c
я определяю прототипы 2-х функций, представленные в version.h
#include "version.h"
/*****************************************************************************/
/**
* @name board_init
*
* Sets up the application based on the version type defined in version.h.
* Includes allowing or prohibiting printing to STDOUT.
*
* MUST BE CALLED FIRST THING IN MAIN
*
* @return None
*
*****************************************************************************/
void board_init()
{
// Assign the print function to the correct function pointer
#ifdef DEBUG_VERSION
zprintf = &printf;
#else
// Defined below this function
zprintf = &noprintf;
#endif
}
/*****************************************************************************/
/**
* @name noprintf
*
* simply returns with no actions performed
*
* @return None
*
*****************************************************************************/
void noprintf(const char* c, ...)
{
return;
}
Обратите внимание на то, как указатель функции прототипирован в version.h
как void (* zprintf)(const char *, ...);
. Когда он ссылается в приложении, он начнет выполнение везде, где он указывает, что еще должно быть определены. В version.c
уведомление в функции board_init()
, где zprintf
назначается уникальная функция (подпись функции которой соответствует) в зависимости от версии, определенной в version.h
zprintf = &printf;
, zprintf вызывает printf для целей отладки или zprintf = &noprint;
zprintf просто возвращает и не будет запускать ненужный код
Запуск кода будет выглядеть следующим образом:
#include "version.h"
#include <stdlib.h>
int main()
{
// Must run board_init(), which assigns the function
// pointer to an actual function
board_init();
void *ptr = malloc(100); // Allocate 100 bytes of memory
// malloc returns NULL if unable to allocate the memory.
if (ptr == NULL)
{
zprintf("Unable to allocate memory\n");
return 1;
}
// Other things to do...
return 0;
}
В приведенном выше коде будет использоваться printf
в режиме отладки или ничего не делать, если в режиме деблокирования. Это намного проще, чем пройти весь проект и комментировать или удалять код. Все, что мне нужно сделать, это изменить версию в version.h
, а код сделает все остальное!