How can I verify that all my init functions have been called?

I am writing a large C program for inline use. Each module in this program has an init () function (for example, a constructor) for setting its own static variables.

The problem is that I have to remember to call all these init functions from main(). I also have to remember to return them if I somehow commented on them.

Is there anything clever to have all these functions invoked? Something like macro lines in every init function, which, after calling the function, check_inited()sends a warning to STDOUT if not all functions are called.

I could increase the counter, but I would need to maintain the correct number of init functions somewhere, and also error prone.

Thoughts?

Below is the solution I made, with the help of several users in this thread

My goal is to make sure that all of my init functions are actually called. I want to do this without saving lists or module counts across multiple files. I can't call them automatically, as Nick D suggested, because they need to be called in a specific order.

To do this, the macro included in each module uses the gcc attribute constructorto add the init function name to the global list.

Another macro, included in the body of the init function, updates the global list to make note that the function was actually called.

Finally, the check function is called in main()after all inits have completed.

Notes:

  • . , . , .

  • "nx_lib". , "nxl".

  • , , .

  • . , .

  • static, , .

  • , , , , , .

:

pierr, constructor.

Nick D ## .

tod frye , .

.

nx_lib_public.h

#define NX_FUNC_RUN_CHECK_NAME_SIZE 20

typedef struct _nxl_function_element{
  char func[NX_FUNC_RUN_CHECK_NAME_SIZE];
  BOOL called;
} nxl_function_element;

void nxl_func_run_check_add(char *func_name);
BOOL nxl_func_run_check(void);
void nxl_func_run_check_hit(char *func_name);

#define NXL_FUNC_RUN_CHECK_ADD(function_name) \
  void cons_ ## function_name() __attribute__((constructor)); \
  void cons_ ## function_name() { nxl_func_run_check_add(#function_name); }

nxl_func_run_check.c

, .

#define MAX_CHECKED_FUNCTIONS 100

static nxl_function_element  m_functions[MAX_CHECKED_FUNCTIONS]; 
static int                   m_func_cnt = 0; 


// call automatically before main runs to register a function name.
void nxl_func_run_check_add(char *func_name)
{
  // fail and complain if no more room.
  if (m_func_cnt >= MAX_CHECKED_FUNCTIONS) {
    print ("nxl_func_run_check_add failed, out of space\r\n");
    return; 
  }

  strncpy (m_functions[m_func_cnt].func, func_name, 
           NX_FUNC_RUN_CHECK_NAME_SIZE);

  m_functions[m_func_cnt].func[NX_FUNC_RUN_CHECK_NAME_SIZE-1] = 0;

  m_functions[m_func_cnt++].called = FALSE;
}

// call from inside the init function
void nxl_func_run_check_hit(char *func_name)
{
  int i;

  for (i=0; i< m_func_cnt; i++) {
    if (! strncmp(m_functions[i].func, func_name, 
                  NX_FUNC_RUN_CHECK_NAME_SIZE)) {
      m_functions[i].called = TRUE;   
      return;
    }
  }

  print("nxl_func_run_check_hit(): error, unregistered function was hit\r\n");
}

// checks that all registered functions were called
BOOL nxl_func_run_check(void) {
  int i;
  BOOL success=TRUE;

  for (i=0; i< m_func_cnt; i++) {
    if (m_functions[i].called == FALSE) {
      success = FALSE;
      xil_printf("nxl_func_run_check error: %s() not called\r\n", 
                 m_functions[i].func);
     } 
  }
  return success;
}

solo.c

,

#include "nx_lib_public.h"

NXL_FUNC_RUN_CHECK_ADD(solo_init)
void solo_init(void)
{
  nxl_func_run_check_hit((char *) __func__);

  /* do module initialization here */
}
+5
8

, , :-)

( - , , atexit. , atexit )

- :

typedef int (*function_t)(void);

static function_t  vfunctions[100]; // we can store max 100 function pointers
static int         vcnt = 0; // count the registered function pointers

int add2init(function_t f)
{
  // todo: error checks
  vfunctions[vcnt++] = f;
  return 0;
}
...

int main(void) {
 ...
 // iterate vfunctions[] and call the functions
 ...
}

... :

typedef int (*function_t)(void);
extern int add2init(function_t f);
#define M_add2init(function_name)  static int int_ ## function_name = add2init(function_name)

int foo(void)
{
   printf("foo\n");
   return 0;
}
M_add2init(foo); // <--- register foo function
+1

gcc extension __attribute__((constructor)), gcc .

#include <stdio.h>
void func1() __attribute__((constructor));
void func2() __attribute__((constructor));

void func1()
{
    printf("%s\n",__func__);
}

void func2()
{
    printf("%s\n",__func__);
}

int main()
{
    printf("main\n");
    return 0;
}

//the output
func2
func1
main
+3

script, . script ... . , ?:)

, , modX.c. init() "void init()"...

script grep .h , init() ed. script, init() main().

+1

Splint (, , Lint) , , .

, , .

+1

, :

static inline void init(void) { ... }
static int initialized = 0;
#define INIT if (__predict_false(!initialized)) { init(); initialized = 1; }
struct Foo *
foo_create(void)
{
    INIT;
    ...
}

"__predict_false" - . , ( ).

+1

- . , init, init. , init .

, init, , .

, : ...

//this is the syntax in GCC..(or would be if the underscores came through in this text editor)
initFuncPtr thisInit __attribute((section(.myinits)))__= &moduleInit;

void moduleInit(void)
{
// so init here
}

init .myinits, .code. .myinits - , . , .

. .

init protoytpe, , .

, , C.

, , , , ...

+1

, " " , , . BEFORE_INIT INITIALIZED.

, , A foo bar.

(.. , ) ​​:

void foo_logic();
void bar_logic();

.

( , foo()), , :

void foo() {
       if (module_state == BEFORE_INIT) {
           handle_not_initialized_error();
       }
       foo_logic();
}

.

:

  • , , , , ( , , ).
  • , , if, - .
  • "-" , /, , , IPC.
  • ++, , . , -, C , .
+1

?

, , Nick D.

, -gstab, init_ *, .

, , -.

However, I do not like this idea because it means that I always need to include debug information in the binary.

0
source

All Articles