开发者

Make a single definition from main.c to be available for a library at compile time

开发者 https://www.devze.com 2023-04-03 07:07 出处:网络
Lets say I开发者_Go百科 have a main.c file #include \"library.h\" #define LIBRARY_VALUE 5 int main(void)

Lets say I开发者_Go百科 have a main.c file

#include "library.h"
#define LIBRARY_VALUE 5

int main(void)
{
    somefunction1();
    return 0;
}

library.h

void somefunction1(void);

library.c

#include "library.h"
#ifndef LIBRARY_VALUE
#define LIBRARY_VALUE 1
#endif

static unsigned char oneString[LIBRARY_VALUE]; // Also I need to be able
                                               // to use the value to initialize
                                               // static arrays that will be
                                               // modified by somefunction1();
void somefunction1(void)
{
    printf("The Library Value is %d\n", LIBRARY_VALUE);
}

What I want to do here, is to be able to compile main.c and having LIBRARY_VALUE‘s value to be used as I defined right after the include in main.c.

How should I use GCC in order to achieve this? I do need the value to be defined in main.c.

In case I have to change my code, I need a minimum working example code please. So I know clearly how to do this. Thanks.


In C there is no way for different .c files to share a common macro defined in one of the .c files. The tradition is to put it in a .h file, but you say this will not work for you.

You will need a type of "constructor" function that sets up your "static" information at run time. This constructor can be called directly by main.c, or indirectly by having main.c define an extern the library picks up.

I'll throw you some code, but I haven't tried to compile it... I'll leave that as an exercise for the student.

main.c

#include "library.h"
int const library_value = 5;

int main(void) { somefunction1(); return 0; }

library.h

extern int const library_value;
void somefunction1(void);

library.c

#include <assert.h>
#include "library.h"

static unsigned char *oneString;

// destroy any memory from lib_init().
static void lib_clear(void)
{
    if ( oneString )
    {
        free(oneString);
        oneString = NULL;
    }
}

// initialization - strop the static if the caller is to start it up.
static void lib_init( void )
{
    if ( ! oneString )             // (defensive "if" to be sure)
    {  
        assert( library_value > 0 );

        oneString = (unsigned char*)malloc( library_value );

        atexit( &lib_clear );
    }    
}


void somefunction1(void)
{
    if ( ! oneString )    // if the main() is not calling an the constructor then
        lib_init();       //  // every method within the library must do so.

    printf("The Library Value is %d\n", library_value);
}

The lib_init() and lib_clear() methods could be made externs with a lib_init( int size ) signature to take the size.


Your goal seems to have a single definition referenced multiple places.

There are a limited number of possibilities:

  1. #define in .h
  2. extern defined in main, or somewhere else outside of library.
  3. extern defined in library.
  4. Value passed by caller to library, perhaps an initialization call for the library.
  5. Something defined before #include library.h that is picked up by library.h. I don't like this one.
  6. As alfa says, make it a compile-time definition.

An example of a #define within library.h.

// library.h
#ifndef LIBRARY_VALUE
#define LIBRARY_VALUE 1

void somefunction1(void);

#endif

Or, have main define a value defined by the caller and referenced by the library:

// library.h
extern int const library_value;   // caller to define in main
void somefunction1(void);         // function for caller
// main.c
int const library_value  = 5;

int main(void)
{
    somefunction1();
    return 0;
}

The one I don't like is:

//main.c
#define LIBRARY_VALUE 5
#include "library.h"
//library.h
#ifdef LIBRARY_VALUE
int const library_value = LIBRARY_VALUE;  // executable code in .h files is evil
#endif

Some of the reasons I dont' like this is that it is obscure and unconventional, if two or more callers of library.h define LIBRARY_VALUE you will, or at least should, get obscure link time errors. The same applies if LIBRARY_VALUE is not defined by an #include... library.c itself can not define a default value. No, I'd much rather call an initialization function for the library that accepts the constant.


The problem with the way you seem to want this to work, is that the constant gets used when the library is compiled -- you can't use one value when compiling the library and then compile a program with a different value and expect the library's code to magically change to use the new constant. You have some options when it comes to alternatives, though.

You could move the array into the program rather than the library, and give the library a pointer to it, and its size.

Or you could use a dynamically allocated array in the library, and add an initialization function to do the allocation (using the size provided by the program).

Or, you could ditch the library and just compile its code as part of the program -- then you can use a constant defined for the program as long as its done where the (previously) library code will see it.


Recommendation (assuming you want "myarray" visible outside the library):

// library.h
#ifndef LIBRARY_H
#define LIBRARY_Y

#define ARRAY_SIZE 5

extern unsigned char myarray[ARRAY_SIZE]; // Also I need to be able
                                          // to use the value to initialize
                                          // static arrays that will be
                                          // modified by somefunction1();
void somefunction1(void);         // function for caller

#endif
/* LIBRARY_H */

Otherwise, if you just want "somefunction1()" and the array size, then declare another function, "array_size ()":

// library.h
#ifndef LIBRARY_H
#define LIBRARY_Y

#define ARRAY_SIZE 5

int array_size ();                // library.c will define "myarray" and it will
                                  // define function array_size as "return ARRAY_SIZE;"
void somefunction1(void);         // function for caller

#endif
/* LIBRARY_H */

ALSO: Please remember that "static" has two meanings:

1) Hides visibility of a variable or function name to file scope (the name is "invisible" outside of the source file)

2) allocates space for the object from static storage (instead of the heap (malloc/new) or stack (local variables)).

If you only want the "static storage" part; then you don't need the keyword "static". Just define your variable outside of a function, and you're set :).

Yet another issue is whether you want to make "ARRAY_SIZE" a compile time variable. If so, you should make sure it gets defined EXACTLY ONCE (when library.c is compiled), and is used IN ONLY ONE PLACE (library.c and library.c only). For example:

// library.c
#include "library.h"

#ifndef ARRAY_SIZE
  #error ARRAY_SIZE IS UNDEFINED!
#else
static unsigned char myarray[ARRAY_SIZE]; 

int array_size ()
{
  return ARRAY_SIZE;
}
#endif
...


What you are trying to do is not possible because library.c and main.c are compiled separately. You should compile library.c with "gcc -DLIBRARY_VALUE=5 ..." instead.

0

精彩评论

暂无评论...
验证码 换一张
取 消