3 façons d'organiser le code multiplateforme

1. Origine

Dans l'article précédent, nous avons partagé une multiplateforme de fichiers d'en-tête pour devenir ce que c'était, ce fichier d'en-tête pour les fenêtres sous la plate-forme plus significatif, car traiter les fonctions de bibliothèque de déclarations d'importation et d'exportation ( dllexport, dllimport ).

En fait, vous pouvez continuer à développer sur la base de ce fichier d'en-tête pour obtenir un contrôle plus fin . Par exemple: le jugement du compilateur, le jugement de la version du compilateur , etc.

De même, nous rencontrerons également des problèmes multiplateformes dans le code source . Différentes fonctions dans différentes plates-formes, la mise en œuvre n'est pas la même , comment organiser ces codes spécifiques à la plate-forme? Cet article parlera de ce problème.

PS: Un exemple de code de construction simple et multiplateforme est fourni à la fin de l'article.

2. Introduction du problème

Supposons que nous écrivions une bibliothèque et que nous devions implémenter une fonction: obtenir l' horodatage du système . En tant qu'auteur de la bibliothèque d'implémentation, vous décidez de fournir les fonctions API suivantes:

t_time.h: déclarer la fonction d'interface (t_get_timestamp);
t_time.c: implémenter la fonction d'interface;

La tâche suivante consiste à calculer l'horodatage actuel du système via différentes bibliothèques C ou appels système dans l' implémentation de la fonction .

Sous la plate-forme Linux , cela peut être réalisé par le morceau de code suivant:

struct timeval tv;
gettimeofday(&tv, null);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;

Sous la plate-forme Windows , cela peut être réalisé par le morceau de code suivant:

struct timeb tp;
ftime(&tp);
return tp.time *1000 + tp.millitm;

La question est donc: comment organiser ensemble ces deux morceaux de code liés à la plateforme ? Voici trois méthodes d'organisation différentes. Il n'y a pas de différence entre les bonnes et les mauvaises. Tout le monde a des habitudes différentes. Il vous suffit de choisir la méthode qui vous convient, à vous et à votre équipe.

En outre, il n'y a que 1 fonction dans cet exemple , et il est relativement court. Si ces fonctions multiplateformes sont nombreuses et très longues, votre choix peut être différent.

Trois, trois solutions

plan 1

Directement dans la fonction d'interface, distinguez les différentes plates-formes grâce aux définitions de macros de plate-forme .

Les définitions de macro de plate-forme ( T_LINUX, T_WINDOWS ) ont été présentées dans l'article précédent. Le système d'exploitation et le compilateur sont utilisés pour déterminer la plate-forme actuelle, puis une définition de macro de plate-forme unifiée est définie pour notre propre usage:

Le code est organisé comme suit:

int64 t_get_timestamp()
{
    int64 ts = -1;
    
#if defined(T_LINUX)
    struct timeval tv;
    gettimeofday(&tv, null);
    ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
#elif defined(T_WINDOWS)
    struct timeb tp;
    ftime(&tp);
    ts = tp.time;
    ts = ts *1000 + tp.millitm;
#endif

    return ts;
}

De cette manière, tous les codes de plate-forme sont placés dans des fonctions API et la compilation conditionnelle est effectuée via des définitions de macros de plate-forme , car le code est relativement court et a l'air bien.

Scénario 2

Placez les codes d'implémentation de différentes plates-formes dans des fichiers séparés , puis utilisez les symboles de prétraitement #include pour introduire des codes liés à la plate-forme dans les fonctions de l'API .

C'est-à-dire ajouter 2 fichiers supplémentaires:

t_time_linux.c: stocker l'implémentation du code sous la plateforme Linux;
t_time_windows.c: stocker l'implémentation du code sous la plateforme Windows;

(1) t_time_linux.c

#include "t_time.h"
#include <sys/time.h>

int64 t_get_timestamp()
{
    int64 ts = -1;
    
    struct timeval tv;
    gettimeofday(&tv, null);
    ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    
    return ts;
}

(2) t_time_windows.c

#include "t_time.h"
#include <windows.h>
#include <sys/timeb.h>

int64 t_get_timestamp()
{
    int64 ts = -1;
    
    struct timeb tp;
    ftime(&tp);
    ts = tp.time;
    ts = ts *1000 + tp.millitm;

    return ts;
}

(3) t_time.c

Ce fichier ne fait rien, il inclut juste un autre code.

#include "t_time.h"

#if defined(T_LINUX)
#include <t_time_linux.c>
#elif defined(T_WINDOWS)
#include <t_time_windows.c>
#else
int64 t_get_timestamp()
{
    return -1;
}
#endif

Certaines personnes sont plus dégoûtées par ce type d'organisation. Généralement, il s'agit d'inclure un fichier d'en-tête .h , mais voici une définition de macro de plate-forme pour inclure différents fichiers sources .c . !

En fait, il existe des bibliothèques open source qui le font, telles que les suivantes:

Schéma 3

Dans le schéma 2 ci-dessus, le code source est rempli de codes d'implémentation de différentes plates-formes.

En fait, vous pouvez changer la façon de penser.Maintenant qu'il a été placé dans différents fichiers selon différentes plates-formes, vous pouvez ajouter différents fichiers source au processus de compilation .

Le code de test est généré à l'aide de l' outil cmake , vous pouvez donc modifier le fichier CMakelists.txt pour contrôler les fichiers source impliqués dans la compilation.

Partie du fichier CMakelists.txt

# 设置平台变量
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(PLATFORM linux)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(PLATFORM windows)
endif()

# 根据平台变量,来编译不同的源文件
set(LIBSRC  t_time_${PLATFORM}.c)

Ce type d'organisation rend le code plus "propre" . De même, nous pouvons également voir que certaines bibliothèques open source font de même:

四 、 Encore une chose

Pour la longueur de l'article, ce qui précède n'est qu'un extrait du code publié.

J'ai écrit l'une des démos les plus simples , en utilisant cmake pour créer des bibliothèques dynamiques multiplateformes, des bibliothèques statiques et des programmes exécutables . Le but d'écrire cette démo est principalement comme un shell pour tester du code lors de l'écriture de l'article.

Sous la plate - forme Linux , compilez manuellement via les instructions cmake; sous la plate - forme Windows , vous pouvez directement compiler et exécuter via l' environnement de développement intégré CLion , ou vous pouvez directement générer la solution VS2017 / 2019 via l'outil cmake .

Cette démo a déjà mis en gite entrepôt dans l'intérêt d'un petit partenaire, merci de laisser un message dans un numéro public: dg36 , vous pouvez recevoir l'adresse de clonage.


Les bons articles doivent être envoyés ; plus vous partagez, plus vous avez de chance!


Lecture recommandée

1. Pointeur de langage C - du principe de niveau inférieur aux compétences sophistiquées, utilisez des graphiques et du code pour vous aider à expliquer en détail
2. Le principe de débogage de base de gdb original est si simple
3. Analyse étape par étape - comment utiliser C pour mettre en œuvre la programmation orientée objet
4. Tout dit L'architecture logicielle doit être stratifiée et divisée en modules, et ce qui doit être fait spécifiquement (1)
5. On dit que l'architecture logicielle doit être stratifiée et divisée en modules, et ce qui devrait être fait spécifiquement (2)

Je suppose que tu aimes

Origine blog.csdn.net/u012296253/article/details/115366970
conseillé
Classement