При разработке модуля вам необходимо решить, нужен ли пользователям этого модуля прямой доступ к полям в структуре, и это определит, где вы в конечном итоге определите структуру.Я опишу несколько разных сценариев:
1.Пользователь (модуля) будет напрямую манипулировать данными GPS в вашей структуре. У вас нет выбора, кроме как определить структуру в файле заголовка (.h) как часть API.Преимущество состоит в том, что этот метод прост и дает пользователю возможность статически или динамически распределять память для вашей структуры по мере необходимости (поскольку структура структуры известна вашим другим модулям).Этот недостаток заключается в том, что этот метод не скрывает ваши данные;он может быть намеренно или случайно поврежден пользователем.
2.Пользователю не важно, что такое «местоположение GPS», он всегда будет использовать функции модуля для работы с вашей структурой данных. В этом случае ваша структура может быть непрозрачной.Вы объявляете это в файле заголовка (.h) и определяете его в файле источника (.c) (как описано в ответе Грэма).Преимущество в том, что вы можете скрыть все свои данные, что означает, что пользователь не может легко их испортить или (в случае собственной библиотеки) понять, как они были реализованы.Недостатком является то, что ваш модуль должен управлять выделением (и освобождением) вашего непрозрачного типа (расширение этой идеи см. В пункте 3 ниже).
gps_system.h
typedef struct _GPSLocation GPSLocation;
void setupGPSSystem(char* navigationSystem, GPSLocation *start, GPSLocation *destination);
gps_system.c
struct _GPSLocation
{
double latitude;
double longitude;
}
3.Вы хотели бы предоставить пользователю доступ только для чтения к некоторым полям, но скрывать другие. Это может быть полезным способом скрытия деталей реализации и предотвращения повреждения данных пользователем, одновременно облегчая доступ к полезной информации.,Недостатком является то, что вам все еще нужен ваш модуль для управления выделением непрозрачного типа.
gps_system.h
typedef struct
{
double latitude;
double longitude;
}
GPSLocation;
/* Create a new GPS object. */
void gps_new(GPSLocation **gps);
/* Set the GPS object's current location. */
void gps_set(GPSLocation *gps, double latitude, double longitude);
/* Calculate the distance from a GPS coordinate to a different location. */
void gps_distance(GPSLocation *gps, double latitude, double longitude);
/* Free all memory allocated to a gps object. */
void gps_delete(GPSLocation *gps);
gps_system.c
struct GPSLocation_private
{
GPSLocation gps_public;
int field_0;
int field_1;
};
/** Convert from the public version of the gps object object to the private. */
#define gps_get_private(gps_public) ((struct GPSLocation_private *)(((char *)(gps_public)) - offsetof(struct GPSLocation_private, gps_public)))
void gps_new(GPSLocation **gps)
{
struct GPSLocation_private *priv;
priv = malloc(sizeof(struct GPSLocation_private));
if (priv)
{
priv->field_0 = 1234;
priv->field_1 = 4567;
priv->gps_public.latitude = 1111;
priv->gps_public.longitude = 2222;
gps = &priv->gps_public;
}
else
{
*gps = NULL;
}
}
void gps_set(GPSLocation *gps, double latitude, double longitude)
{
struct GPSLocation_private *priv;
priv = gps_get_private(gps);
/* Do stuff with 'priv'. */
}
void gps_delete(GPSLocation *gps)
{
struct GPSLocation_private *priv;
priv = gps_get_private(gps);
free(priv);
}