Сделайте одно определение из main.c, которое будет доступно для библиотеки во время компиляции - PullRequest
0 голосов
/ 05 сентября 2011

Допустим, у меня есть main.c файл

#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);
}

Что я хочу сделать здесь, так это уметь компилировать main.c и иметь значение LIBRARY_VALUE , которое будет использоваться, как я определил сразу после , включая в main.c .
Как мне использовать GCC для достижения этой цели? Мне нужно значение, которое должно быть определено в main.c .

В случае, если мне нужно изменить свой код, мне нужен минимальный рабочий пример кода, пожалуйста. Так что я четко знаю, как это сделать. Спасибо.

Ответы [ 5 ]

0 голосов
/ 07 сентября 2011

В C нет возможности для разных файлов .c использовать общий макрос, определенный в одном из файлов .c.Традиция заключается в том, чтобы поместить его в файл .h, но вы говорите, что это не сработает для вас.

Вам понадобится тип функции «конструктор», которая устанавливает вашу «статическую» информацию во время выполнения.Этот конструктор может быть вызван напрямую из main.c или косвенно, если main.c определит extern, который берет библиотека.

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

main.c

#include "library.h"
int const library_value = 5;</p>

<p>int main(void)
{
    somefunction1();
    return 0;
}</p>

<p>
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);
}

Методы lib_init () и lib_clear () можно сделать внешними с помощью lib_init (int size) для получения размера.

0 голосов
/ 05 сентября 2011

Рекомендация (при условии, что вы хотите, чтобы «myarray» был виден за пределами библиотеки):

// 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 */

В противном случае, если вы просто хотите «somefunction1 ()» и размер массива, тогда объявите другую функцию «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 */

ТАКЖЕ: пожалуйста, помните, что" static "имеет два значения:

1) Скрывает видимость имени переменной или функции в области видимости файла (имя" невидимый ")вне исходного файла)

2) выделяет место для объекта из статического хранилища (вместо кучи (malloc / new) или стека (локальные переменные)).

Если вы хотите толькочасть «статическое хранилище»;тогда вам не нужно ключевое слово "статический".Просто определите вашу переменную вне функции, и вы установите:).

Еще одна проблема - хотите ли вы сделать "ARRAY_SIZE" переменной времени компиляции.Если это так, вы должны убедиться, что он определен ТОЛЬКО ОДИН РАЗ (когда библиотека.c скомпилирована) и используется ТОЛЬКО ОДНОМ МЕСТЕ (только для library.c и library.c).Например:

// 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
...
0 голосов
/ 05 сентября 2011

Кажется, ваша цель содержит одно определение, на которое ссылаются несколько мест.

Количество возможностей ограничено:

  1. # определить в .h
  2. extern, определенный в main или в другом месте за пределами библиотеки.
  3. extern определено в библиотеке.
  4. Значение, переданное вызывающей стороной в библиотеку, возможно, вызов инициализации для библиотеки.
  5. Что-то определенное до #include library.h, которое поднято library.h. Мне не нравится этот
  6. Как говорит альфа, сделайте это определение во время компиляции.

Пример #define в файле library.h.

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

void somefunction1(void);

#endif

Или, пусть main определяет значение, определенное вызывающей стороной и на которое ссылается библиотека:

// 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;
}

Мне не нравится:

//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

Некоторым из причин, по которым мне это не нравится, является то, что это неясно и нетрадиционно, если два или более вызывающих библиотеки. H определяют LIBRARY_VALUE, вы будете, или, по крайней мере, должны получать неясные ошибки времени соединения. То же самое применимо, если LIBRARY_VALUE не определен #include ... library.c, сам не может определить значение по умолчанию. Нет, я бы скорее вызвал функцию инициализации для библиотеки, которая принимает константу.

0 голосов
/ 05 сентября 2011

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

Вы можете переместить массив в программу, а не в библиотеку, и дать библиотеке указатель на нее и ее размер.

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

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

0 голосов
/ 05 сентября 2011

То, что вы пытаетесь сделать, невозможно, потому что library.c и main.c скомпилированы отдельно.Вы должны скомпилировать library.c с помощью "gcc -DLIBRARY_VALUE = 5 ...".

...