J'écris un programme multiplateforme. Je veux que ce programme s'exécute sous Windows et Linux, j'ai donc deux segments de code différents pour les deux plates-formes. Si le système d'exploitation est Windows, je veux que le premier segment de code s'exécute; si c'est Linux, je veux que le deuxième segment de code s'exécute.
J'ai donc écrit le code suivant, mais il obtient une erreur lors de la construction à la fois sur Windows et sur Linux. Que dois-je faire pour le résoudre?
#ifdef __unix__ /* __unix__ is usually defined by compilers targeting Unix systems */
#define OS_Windows 0
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#Elif defined(_WIN32) || defined(WIN32) /* _Win32 is usually defined by compilers targeting 32 or 64 bit Windows systems */
#define OS_Windows 1
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define DIV 1048576
#define WIDTH 7
#endif
int main(int argc, char *argv[])
{
if(OS_Windows)
{
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
_tprintf (TEXT("There is %*ld %% of memory in use.\n"),
WIDTH, statex.dwMemoryLoad);
}
else if(!OS_Windows) // if OS is unix
{
char cmd[30];
int flag = 0;
FILE *fp;
char line[130];
int memTotal, memFree, memUsed;
flag=0;
memcpy (cmd,"\0",30);
sprintf(cmd,"free -t -m|grep Total");
fp = popen(cmd, "r");
while ( fgets( line, sizeof line, fp))
{
flag++;
sscanf(line,"%*s %d %d %d",&TotalMem, &TotalUsed, &TotalFree);
}
pclose(fp);
if(flag)
printf("TotalMem:%d -- TotalUsed:%d -- TotalFree:%d\n",TotalMem,TotalUsed,TotalFree);
else
printf("not found\n");
}
return 0;
}
C'est généralement fait comme ça (plus ou moins):
#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define DIV 1048576
#define WIDTH 7
#endif
#ifdef linux
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#endif
int main(int argc, char *argv[])
{
#ifdef _WIN32
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
_tprintf (TEXT("There is %*ld %% of memory in use.\n"),
WIDTH, statex.dwMemoryLoad);
#endif
#ifdef linux
char cmd[30];
int flag = 0;
FILE *fp;
char line[130];
int TotalMem, TotalFree, TotalUsed;
flag=0;
memcpy (cmd,"\0",30);
sprintf(cmd,"free -t -m|grep Total");
fp = popen(cmd, "r");
while ( fgets( line, sizeof line, fp))
{
flag++;
sscanf(line,"%*s %d %d %d",&TotalMem, &TotalUsed, &TotalFree);
}
pclose(fp);
if(flag)
printf("TotalMem:%d -- TotalUsed:%d -- TotalFree:%d\n",TotalMem,TotalUsed,TotalFree);
else
printf("not found\n");
#endif
return 0;
}
De cette façon, seul le code pour linux sera compilé sur une plateforme linux, et seul le code windows sera compilé sur une plateforme windows.
Vous devez utiliser la même logique #ifdef
Au lieu de la logique if(OS_Windows)
dans votre code:
#ifdef __unix__
...
#Elif defined(_WIN32) || defined(WIN32)
#define OS_Windows
#endif
int main(int argc, char *argv[])
{
#ifdef OS_Windows
/* Windows code */
#else
/* GNU/Linux code */
#endif
}
Je vois beaucoup de solutions différentes ici, ce qui me met mal à l'aise ... Et si elles fonctionnent sur Linux mais pas Windows ou sur Windows mais pas Linux? Et s'ils ne fonctionnent que sur certains compilateurs? Etc.
J'ai donc trouvé ce lien, que j'aime: http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
Il semble que ce sont les meilleurs (en utilisant #ifdef, #endif, etc.):
_WIN32
pour Windows 32 bits_WIN64
pour Windows 64 bits__unix__
pour UnixVous confondez des variables (qui existent au moment de l'exécution) avec des symboles de préprocesseur (qui n'existent que lors de la compilation).
Après avoir fait quelque chose comme #define OS_Windows 1
, Vous ne pouvez pas utiliser le symbole OS_Windows comme variable et le mettre dans if()
s ... Je veux dire, vous pouvez, mais il sera développé lors de la compilation à if (1)
.
Pour un projet multiplateforme, vous devez utiliser #if
Ou #ifdef
pour vous assurer que le compilateur choisit une partie correcte de code pour un système d'exploitation donné et - compile seulement cela.
Quelque chose comme:
void openWindow() {
#if OS_Windows
// windows-specific code goes here
#else
// linux-specific code
#endif
}
Votre stratégie de base est profondément défectueuse.
En utilisant le if dans la fonction principale, vous sélectionnez le bloc de code à exécuter à RUNTIME. Ainsi, même si vous compilez pour Unix, le compilateur doit toujours construire le code pour Windows (ce qu'il ne fait pas parce que les fichiers d'en-tête ne sont pas inclus) et vice versa.
Au lieu de cela, vous avez exigé #if qui sera évalué au moment de la compilation et ne tentera pas de compiler du code non pertinent.
Donc, en substance, vous devez comprendre que si évalue votre définition en tant qu'expression au moment de l'exécution alors que #if évalue la valeur de la constante prédéfinie au moment de la compilation.