Ответ 1
Почему бы не использовать статическую инициализацию?
struct A a = { 42 };
Каков наилучший способ выполнить следующее в C?
#include <stdio.h>
struct A
{
int x;
};
struct A createA(int x)
{
struct A a;
a.x = x;
return a;
}
struct A a = createA(42);
int main(int argc, char** argv)
{
printf("%d\n", a.x);
return 0;
}
Когда я пытаюсь скомпилировать вышеуказанный код, компилятор сообщает о следующей ошибке:
"элемент инициализации не является константой"
Плохая строка:
struct A a = createA(42);
Может кто-нибудь объяснить, что не так? Я не очень опытен в C. Спасибо!
Почему бы не использовать статическую инициализацию?
struct A a = { 42 };
struct A a = { .x = 42 };
Больше участников:
struct Y {
int r;
int s;
int t;
};
struct Y y = { .r = 1, .s = 2, .t = 3 };
Вы также можете сделать
struct Y y = { 1, 2, 3 };
То же самое работает для профсоюзов, и вам не нужно включать всех членов или даже помещать их в правильном порядке.
Проблема здесь в том, что статические переменные global/file в C должны иметь значение, известное во время компиляции. Это означает, что вы не можете использовать определенную пользователем функцию для инициализации значения. Это должно быть постоянное выражение
Вы не можете вызывать функции в статической инициализации. В вашем примере вы можете просто использовать:
struct A a = {42};
Если у вас более сложная настройка, вам нужно будет создать функцию построения библиотеки и уничтожения библиотеки, которая заставит пользователей вашей библиотеки звонить (при условии, что вы хотите быть переносимыми), или вам придется использовать С++ и принимать преимущество конструкторов/деструкторов, или вам придется использовать нестандартный и не переносимый __ атрибут __ ((конструктор)) для создания функции, запускаемой при запуске, для ее инициализации.
Если у вас более сложная настройка, я бы решительно выступал за то, что вы используете С++:
class A { A(){ // can do initialization in the constructor } // ... }; A a;
Однако, если вам нужно придерживаться чистого C, переносная вещь, которую нужно сделать, это использовать что-то вроде:
typedef void* mylibrary_attr_t; typedef void* mylibrary_t; #ifdef __cplusplus # define EXTERNC extern "C" #else # define EXTERNC #endif EXTERNC int mylibrary_attr_init(mylibrary_attr_t*); EXTERNC int mylibrary_attr_setparam1(mylibrary_attr_t,int); EXTERNC int mylibrary_attr_setparam2(mylibrary_attr_t,double); // .. more functions for various attributes used by library EXTERNC void mylibrary_attr_destroy(mylibrary_attr_t*); EXTERNC int mylibrary_init(mylibrary_t*,mylibrary_attr_t); EXTERNC void mylibrary_destroy(mylibrary_t*); // functions that use mylibrary_t // ...
В основном, в вышесказанном, вы должны инициализировать свою библиотеку с помощью mylibrary_init
и разрывать вашу библиотеку с помощью mylibrary_destroy
. Для функций, использующих вашу библиотеку, потребуется инициализированный экземпляр mylibrary_t
, и поэтому человек, создавший основную функцию, будет отвечать за вызов mylibrary_init
. Также полезно сделать функцию инициализации зависимой от параметра "attributes", который может быть заменен на 0 или NULL по умолчанию. Таким образом, если вы расширяете свою библиотеку и должны принимать параметры конфигурации, она доступна вам. Тем не менее, это больше, чем технический подход.
Для любопытных людей, которые также используют MSVC:
В C можно запускать функции инициализации до main так же, как это возможно в С++ (конечно же, как С++ сделает это, если это невозможно в C), однако это может быть несколько запутанным, если вы не прочитали, как работает ваша библиотека времени выполнения.
Короче говоря:
#pragma section(".CRT$XIU",long,read)
int
init_func ()
{
// initialization
return 0; // return 0 is mandatory
}
__declspec(allocate(".CRT$XIU"))
int (*global_initializer)() = init_func;
Так что это не такой компактный исходный текст, как в С++, но это можно сделать. Кроме того, перед использованием я рекомендую сначала разобраться в формате PE, а затем прочитайте crt\src\crt0.c и crt\src\crt0dat.c(выполните поиск _cinit в обоих файлах) в каталоге установки MSVC, чтобы вы знали, что происходит.
Вы не можете вызвать функцию как initiliazer. Вы должны вызвать его внутри main.