Partage
  • Partager sur Facebook
  • Partager sur Twitter

Foire Aux Questions — langage C

Votre question y est peut-être...

28 avril 2007 à 18:48:19

[8][4] Comment récupérer la date et/ou l'heure ?

Toutes les fonctions utilisées dans cette question sont présentes dans l'en-tête <time.h>.

La première étape est de récupérer le timestamp.
Pour cela rien de bien dur :

time_t temps = time(NULL);

On peut d'ailleurs vérifier qu'on a la bonne valeur en l'affichant :

printf("%ld\n", temps);

Maintenant il nous faut se servir d'une fonction qui va déduire la date et l'heure à partir du timestamp.
Cette fonction c'est ``ctime". Elle prend l'adresse de la variable contenant le timestamp en paramètre et en ressort une chaîne de caractères contenant toutes les informations.

time_t temps = time(NULL);
printf("%s", ctime(&temps));

Donnera par exemple :
Sat Apr 28 15:19:06 2007


On peut aussi contrôler plus finement les informations qu'on veut afficher.
Pour cela, il faut passer par une "conversion" du timestamp en une structure de type `tm'.
La fonction ``localtime" s'en occupe très bien en nous renvoyant l'horaire locale, contrairement à ``gmtime" qui renvoie l'horaire <acronym title="universal time coordinated">UTC</acronym>.

/* on récupère le timestamp */
time_t timestamp = time(NULL);
/* on le convertit dans une instance de la structure tm */
struct tm *temps = localtime(&timestamp);

Comme vous pouvez le voir sur la page de documentation de la structure `tm', celle ci contient toutes les informations que nous voulons.
Nous pouvons donc afficher l'heure par exemple en faisant simplement :

printf("%d\n", temps->tm_hour);

Ce qui chez moi donne :
16

Méfiez vous tout de même, ça parait évident mais le programme vous affichera l'heure de votre système d'exploitation. Ainsi sur mon système qui a 2 heures de retard (allez savoir pourquoi Image utilisateur), le programme m'affiche 16 sans vergogne alors qu'il est 18 heures en réalité...

A partir de votre instance de tm, vous pouvez aussi afficher tout d'un coup, grâce à ``asctime"

time_t timestamp = time(NULL);
struct tm *temps = localtime(&timestamp);
printf("%s", asctime(temps));

Donnera :
Sat Apr 28 15:19:06 2007


Ou vous pouvez enfin formater seulement les informations qui vous intéressent dans une chaîne de caractères grâce à ``strftime".

/* on récupère le timestamp */
time_t timestamp = time(NULL);
/* on crée une chaîne suffisamment longue */
char chaineSortie[20];
/* on convertit le timestamp dans une instance de la structure tm */
struct tm *temps = localtime(&timestamp);
/* on récupère les infos qu'on veut dans la chaîne */
strftime (chaineSortie, 20, "Il est %H:%M:%S", temps);
/* on affiche le tout */
printf ( "%s", chaineSortie);

Donnera par exemple :
Il est 16:48:24


Comme vous le voyez, ce sont les formateurs %H, %M, ... qui indiquent ce qui atterrira dans votre chaîne.
Pour la liste complète, reportez vous sur la page de documentation.
La seule chose dont il faut se méfier c'est de créer une chaîne suffisamment longue. ;)
  • Partager sur Facebook
  • Partager sur Twitter
30 avril 2007 à 0:50:18

[2][5] Comment afficher des caractères accentués sous Windows ?
Par défaut, la console de Windows utilise un encodage hérité du temps de MS-DOS (l'encodage IBM 850), qui ne permet pas d'afficher les caractères accentués ou les caractères spéciaux comme ©, ®, «, », etc.

Toutefois, l'encodage utilisé par la console de Windows est modifiable à volonté, par la commande chcp (CHange CodePage) intégrée à l'interpréteur de commandes. Ainsi, entrer cette commande
chcp 1252

indiquera à votre console d'utiliser la "page de code 1252", qui est un encodage très proche du Latin-1, idéal pour la langue française.

Il n'est alors nul besoin de modifier vos programmes (ni même de les recompiler), les accents et autres caractères spéciaux s'afficheront sans problèmes.

Une autre possibilité consiste à changer l'encodage directement depuis le code de votre programme, en utilisant la fonction appropriée de l'API Windows, SetConsoleOutputCP(). Dans ce cas, une bonne pratique consiste à récupérer l'encodage utilisé au démarrage du programme afin de pouvoir le restaurer à la sortie.
#include <windows.h> /* pour les fonctions GetConsoleOutputCP et associées */
 
/* Au début du programme, on récupère l'encodage
 * utilisé par la console. */
UINT default_codepage = GetConsoleOutputCP();
 
/* Puis, on change cet encodage pour imposer celui
 * que l'on veut (ici, page de code 1252). */
SetConsoleOutputCP(1252);
 
/* Le corps du programme. */
 
/* A la fin du programme, on restaure l'encodage initial. */
SetConsoleOutputCP(default_codepage);


Quelle que soit la méthode retenue, si vous utilisez la console Windows "standard", il faut encore changer la police utilisée par celle-ci pour la remplacer par une police capable d'afficher des caractères accentués : clic-droit sur la barre de titre de la console, "Propriétés", dans l'onglet "Police", choisissez la police "Lucida Console". En fermant la fenêtre, sélectionnez "Enregistrer les propriétés pour les futures fenêtres portant le même titre". Notez que ce n'est pas nécessaire si vous utiliser le nouvel interpréteur de commandes de Microsoft, PowerShell.

Autre possibilité, ne nécessitant aucune configuration de la console cible (au niveau de la fonte comme de l'encodage), l'utilisation des fonctions CharToOem ou CharToOemBuffer de l'API Windows :
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
 
int main(void)
{
    char texte[20] = "";
    CharToOemBuff("éééààà!", texte, sizeof texte - 1);
    puts(texte);
    return 0;
}

(Merci à tc pour avoir suggéré cette solution. :) )
  • Partager sur Facebook
  • Partager sur Twitter
1 mai 2007 à 20:52:21

[5][1]Comment Configurer son compilateur ?

Le mieux est d'aller sur le site d' Emmanuel Delahaye ou tout y est bien expliqué : ici
  • Partager sur Facebook
  • Partager sur Twitter
4 mai 2007 à 12:06:02

[4][1] Comment transformer ma chaîne de caractères en une valeur (int, float) ?

Si vous possédez une chaîne de caractères tel que :
char number[] = "12";

Il vous est possible d'extraire le nombre que représente cette chaîne afin d'obtenir une variable de type long valant 12.

Pour cela, vous pouvez utiliser la fonction strtol() :
#include <stdlib.h>

char number[] = "12";
long var = strtol(number, NULL, 0);

/* ici, var = 12 */

Il est aussi possible de convertir des nombres flottants.
Pour cela, utilisez strtod() :
#include <stdlib.h>

char number[] = "12.5";
double var = strtod(number, NULL);

/* ici, var = 12.5 */


Un exemple d'utilisation pratique est disponible ici :
http://www.siteduzero.com/tuto-3-11181 [...] -a-fgets.html

Pour convertir une chaîne formatée, vous pouvez utiliser sscanf() :
#include <stdio.h>
#include <stdlib.h>

int var1, var2;
char number[] = "12 25";

sscanf(number, "%d %d", &var1, &var2);

/* ici, var1 = 12 et var2 = 25 */

La fonction sscanf renvoie un entier représentant le nombre de conversions réussis, il peut être bon de tester cette valeur afin de savoir si elle correspond aux nombres de conversions que l'on a demandé (2 dans notre cas), si elle est inférieur, il y a une erreur de format.

Pour plus de précisions sur l'utilisation des fonctions strto* et *scanf, reportez-vous aux pages de man :


Avec l'aimable participation de :
- asmanur
- scriptoff
- Zulon
  • Partager sur Facebook
  • Partager sur Twitter
5 mai 2007 à 12:07:59

[8][6] Que signifie le signe # dans une macro ?

Cela demande au préprocesseur d'encadrer la variable qui suivra # par des guillemets.

Voici un exemple :
#define PRINTINT(var) printf("%s = %d\n", #var, var)

int ma_variable = 2;
int mon_autre_variable = 0;

PRINTINT(ma_variable);
PRINTINT(mon_autre_variable);

ma_variable = 2

mon_autre_variable = 0

Au premier appel de la macro PRINTINT par exemple, le préprocesseur remplacera cet appel par cette ligne de code :
printf("%s = %d\n", "ma_variable", ma_variable)

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
10 mai 2007 à 0:13:23

[1][6]Comment peut-on lire une chaîne de caractères contenant des blancs (espaces, tabulations, etc.)?

D'abbord, je tiens à préciser que scanf est mal ! (voir FAQ [1][1]).


La commande associée a scanf pour pouvoir lire des chaînes de caractères comportant des blancs est :
scanf("%[^\n]", ch);
getchar();


Lien informatif :
scanf démythifiée
Entrée solide en C

  • Partager sur Facebook
  • Partager sur Twitter
11 mai 2007 à 15:46:17

[5][2] Comment compiler sous Vista avec MinGW/GCC ?

Code::Blocks et MinGW



Cette partie est désormais obsolète, Code::Blocks est maintenant compatible avec Vista. je vous conseil donc de lire le tuto de Nesquik69 et Xaviou : http://www.siteduzero.com/tutoriel-3-2 [...] e-blocks.html


Le compilateur et le Code::Blocks


Il vous faut déjà tout le matériel nécessaire :


Comme le dit Nesquik69 dans son tutoriel, ne changez surtout pas le lieu d'installation !!!


Configurons MinGW




Je ne ferais là que citer ce message :

Citation : forum hard ware

- Déplacer les fichiers suivant :
C:\MinGW\libexec\gcc\mingw32\3.4.5\cc1.exe => C:\MinGW\bin\cc1.exe
C:\MinGW\libexec\gcc\mingw32\3.4.5\cc1plus.exe => C:\MinGW\bin\cc1plus.exe
C:\MinGW\libexec\gcc\mingw32\3.4.5\collect2.exe => C:\MinGW\bin\collect2.exe


utilisez C:\MinGW\include et C:\MinGW\lib pour installer vos APIs



il se peut que se ne soit pas 3.4.5, cela revient au même !


Configurons C::B



Cette étape est peut-être facultative ! Mais vérifier toujours au cas où


Aller dans settings => Compiler and debugger...

Une fenêtre s'ouvre, sélectionnez GNU GCC Compiler dans la première liste déroulante puis toolchain executables dans la deuxième, cliquez sur auto-detect. Si dans la boîte texte à coté s'affiche C:\MinGW alors c'est bon ! sinon, recopier tout ce qu'il y a sur le screen ci-dessous :
Image utilisateur
Cliquez pour agrandir

Le Set as default sert juste à dire que vous utilisez ce compilateur par défaut, je le précise pour ceux qui ont utilisé VC++ Express édition® avant MinGW.


Je crois qu'il faut relancer l'IDE en suite, à vérifier.

Maintenant, vous devez mettre vos <acronym title="librairies">bibliothèques</acronym> dans le dossier C:\MinGW\includes\ et C:\MinGW\libs\


Dev-C++ et Cygwin



Là c'est extrêmement simple :
Aller, une petite aide : Lien de tréléchargement de cygwin


http://www.siteduzero.com/forum-83-122 [...] html#r1111270
http://www.siteduzero.com/forum-83-122 [...] html#r1111980



Et surtout, n'oubliez pas de relancez l'IDE !!!

ou encore :
http://www.siteduzero.com/forum-83-124 [...] html#r1124904



Vous pouvez maintenant compiler sous Vista avec Dev-C++
  • Partager sur Facebook
  • Partager sur Twitter
18 mai 2007 à 12:51:16

[7][9]Les bases de gdb

Sous linux , aprés avoir compilé votre binaire avec le support debug( "-g" )

gdb votrebinaire


vous obtenez ceci :
-> (gdb)

je vais vous indiquer les commandes les plus utile :
r -> run , execute le binaire .
Si le problème de votre programme est un segfault , il s'arreteras à la ligne de votre code qui le provoque .

b-> breakpoints , interrompt le programme .
vous pouvez utiliser un numèros de ligne , une fonction .
permet d'explorer une fonction de votre code et vous executé le programme ligne par ligne , n-> ligne suivante .

l-> list , liste le code source .
Vous pouvez utiliser un nombre pour indiquer la ligne du milieu qu'il vas afficher .


p-> print , affiche une variable .
Il affiche tout ce que l'on veut : chaine de caractères , entiers.

q->quit , pour quitter

La complétion peut ètre utiliser via la touche tabulation.

Plus d'informations dans ce tutoriel.
  • Partager sur Facebook
  • Partager sur Twitter
7 juin 2007 à 20:54:26

[7][3]Comment créer un OS ?

Faire un « vrai » OS, même s'il n'est qu'en console, est long et compliqué (si on veut avoir un truc correct, je ne parle pas d'un OS qui affiche «hello world» puis ne fait rien). Il va vous falloir plusieurs choses.

Pour faire un OS, donc, il vous faudra un langage de programmation tel que le C, mais aussi un assembleur (et faire de l'assembleur).
La toute première partie de votre OS, celle qui démarre l'ordi (le boot loader) doit être écrite en assembleur (à moins que vous preniez un soft qui fait le travail à votre place, comme GRUB).
Ensuite, certaines autres portions critiques seront faites en assembleur. Le reste, vous pouvez le coder en C.
Voici quelques liens pour vous orienter :

Le plus important et ce par quoi vous devriez commencer : un système d'exploitation, c'est quoi ?
Selon CommentCaMarche.net
Selon Wikipedia

Quelques systèmes d'exploitation et/ou noyaux que vous pouvez étudier :
Pépin OS, un tutoriel construit autour d'un exemple.
SOS (Simple OS), un OS tout simple dont vous pouvez étudier le code source.
Minix, un autre code intéréssant à étudier
proorOS, en C++, mais aussi utilisable (pour le boot sector par exemple)
Kernel Linux 1.0 ...

Tutoriaux sur les notions de système d'exploitation
PelleGrini sur developpez
Pagnotte sur developpez
Un autre cours, en PDF

Ajout : un post d'informaticienzero sur ce sujet.

Citation : informaticienzero

Faire un système d'exploitation est un des projets qui tente le plus un programmeur débutant : il suffit de voir le nombre de topics qui y sont dédiés sur Internet pour s'en rendre compte. Cependant, beaucoup de débutants échouent dans leur projet puisque celui-ci est trop conséquent. Bien souvent, ils pensent que faire un système d'exploitation est facile parce qu'ils considèrent que Linus Torvald et Bill Gates ont réussi en étant seul ou peu nombreux. Malheureusement, comme quasiment tous les gros projets initiés par des débutants, le leur coule une semaine après son lancement.

Faire un système d'exploitation, c'est comme n'importe quel autre projet : ce n'est pas impossible, juste difficile. Le tout est de savoir se fixer des limites. En effet, la très grande majorité des débutants qui se lancent dans cet objectif s'imaginent avoir un super-OS qui rivalise avec Linux et Windows, voire même plus beau et performant. Pourtant, si jamais tu veux mener ton projet à bien, il faut être modeste et commencer par un embryon de noyau à peine capable d'afficher un message. Ensuite, tu pourra commencer à ajouter des éléments au fur et à mesure : un gestionnaire d'interruptions, la segmentation, un pilote clavier, la pagination, l'accès au disque dur, etc. Comme tout projet conséquent, il faut commencer bas mais viser haut (cf.Dam's, encore une fois).

Cependant, à cette condition inhérente à tout gros projet, il faut encore en rajouter plusieurs autres, ce qui complexifie évidemment le projet. En effet, créer un système d'exploitation réclame plusieurs compétences si tu veux mener à bien ton projet.

  • La plus évidente, c'est de bonnes compétences en programmation, et dans plusieurs langages en prime. Pour faire un système d'exploitation, il faut connaitre au minimum deux langages de programmation. Le premier, c'est l'assembleur. On ne peut pas y couper puisque certaines parties d'un noyau sont codées directement en assembleur : le boot, le chargement de l'IDT et de la GDT, ou l'activation / désactivation des interruptions par exemple. Le second langage à connaitre, c'est celui avec lequel le reste du noyau sera codé. Techniquement, n'importe quel langage peut faire l'affaire : le C, le C++, le D, le Pascal, le FORTRAN voire même Java ou C#. Le tout est de prendre un langage qui permette d'insérer directement des portions de code assembleur dans le code source. Il faut aussi être à l'aise avec tout ce qui est manipulation de bits, masques binaires et autres opérations de bas-niveau et par extension être à l'aise avec le langage utilisé. Personnellement, mon dévolu se jette sur le C qui est à la base, rappelons-le, un langage conçu pour la programmation système (et donc les OS), et qui permet de faire des opérations sur les bits, d'intégrer des portions de code assembleur (cette capacité n'est pas standard et dépend du compilateur) tout en ayant une bibliothèque standard légère (ce qui la rend plus facile à réécrire par rapport à d'autres langages). Le D est aussi un très bon choix puisque en plus d'être compatible avec le C, l'ajout de portions de code assembleur est standard. L'inconvénient est que la bibliothèque standard est plus conséquente.

  • Un deuxième pré-requis c'est de bonnes connaissances sur l'architecture cible. Si tu veux développer un système d'exploitation pour une architecture X, il faut alors que tu en apprennes plus dessus. Personnellement, je nomme l'architecture x86, non pas parce qu'elle est élégante (loin de là), mais parce qu'elle est la plus répandue (tous les PC se basent sur cette architecture, et même les Mac depuis quelques temps). De nombreux sites internet et de nombreuses documentations sont disponibles sur tous les aspects de cette architecture, et comme référence ultime, il y a la documentation du processeur. Il faut aussi avoir quelques connaissances sur les formats de fichiers, les formats exécutables, etc. Se documenter sur le fonctionnement d'un système d'exploitation et sur les différents éléments qui le composent est aussi très important.

  • La troisième compétence, c'est un bon environnement de développement. On ne peut pas faire un système d'exploitation en compilant simplement sous un IDE. Il faut une panoplie d'outils différents (un compilateur, un assembleur, un linker, un éditeur de texte, un émulateur (pour éviter de redémarrer chaque fois que l'on veut tester le système), etc. Encore une fois, mon avis est personnel mais Linux est un bon choix. La licence est libre (on peut développer un nouveau système d'exploitation sans problème), les outils nombreux et efficaces (GCC par exemple est un ensemble de compilateurs pour plusieurs langages), le shell permet de faire de nombreuses opérations avec tout un tas d'options (il suffit de regarder les options de compilation de GCC pour s'en rendre compte).

  • La dernière qualité, et sans doute la plus importante, c'est la modestie et l'humilité. Je me répète, mais c'est le plus important quand on code un système d'exploitation (par extension n'importe quel projet conséquent). En effet, faire un système d'exploitation est un travail long, fastidieux et bien souvent peu gratifiant (qui se rend compte du travail fourni pour faire une pagination efficace quand il lance une application utilisateur ?). Même faire un mini-système d'exploitation n'est pas facile, donc pas la peine d'essayer de refaire Windows ou Linux avec une super interface graphique.



Bien sur, il faut aussi rajouter à ça de l'organisation, de la rigueur, de la propreté dans le codage, etc. En tous cas, le but de ce petit pavé était de montrer que l'écriture d'un petit système d'exploitation n'est pas impossible mais juste difficile. Si néanmoins tu pense pouvoir mener ton projet à bien, je te propose quelques liens qui peuvent t'être utiles :

  • OSDev, un wiki en anglais assez complet qui aborde de nombreux points sur la conception d'un système d'exploitation. Je te conseille tout particulièrement de lire la première section "Introduction".
  • Pépin, un système d'exploitation créé pour illustrer le tutoriel sur la création d'un noyau minimal. C'est un site intéressant, mais qui n'est pas assez généraliste à mon gout.
  • BrokenThorn Entertainment, un autre site en anglais sur la création d'un système d'exploitation. Il est assez semblable au précédant, mais aborde plus de domaines.
  • Bona Fide OS Development, une série d'articles en anglais sur les différentes parties d'un système d'exploitation.
  • Minix, un système d'exploitation créé par Andrew Tanenbaum pour illustrer ses cours sur la programmation système. Il est intéressant à décortiquer.
  • Logram : un système d'exploitation (qui est devenu une distribution Linux) 64 bits créé par un membre du SdZ. Il est intéressant d'étudier les sources des premières versions qui ne sont pas très volumineuses.
  • [Experts seulement]Linux : si l'on s'y connait bien, il est très intéressant de se plonger dans le code source de Linux. A noter que cela s'applique à tous les systèmes d'exploitation libres qui existent.



En conclusion, faire un petit système d'exploitation n'est pas impossible à condition d'avoir de solides compétences dans les domaines ci-dessus et surtout de l'humilité et de la modestie. En travaillant dur et en restant humble, tu pourra peut-être arriver un jour à faire un petit noyau fonctionnel, et là tu pourra être fier.



Merci à ramiK pour sa contribution ! Si vous avez des adresses à ajouter, envoyez-moi un MP.
  • Partager sur Facebook
  • Partager sur Twitter
J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
15 juin 2007 à 18:10:44

[6][1] Quand je compare ma variable avec un nombre dans un if, la condition est toujours vraie, même si elle n'est pas sensée l'être. Pourquoi ?

Probablement parceque vous vous êtes trompé d'opérateur. Vous avez utilisé '=' au lieu de '=='.

Mauvais exemple :
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char buffer[32];
    int age = -1;

    /* Saisie de l'age */
    do
    {
        fgets(buffer, 32, stdin);
    } while( sscanf(buffer, "%d", &age) < 1); 

    /* Bon je vous passe le nettoyage du buffer ici, mais
       theoriquement faudrait le faire */

    /* Le probleme se situe ici : il faut toujours deux '=' dans les conditions !! */
    if(age = 18) /* ERREUR */
    {
        puts("Vous etes devenu majeur cette annee !");
    }
    else
    {
        puts("Vous n'avez pas atteint votre majorite cette annee ci.");
    }

    return 0;
}


Correction :
/* Le reste du code est identique */
if(age == 18)
{
/* ... ... ... */


Que se passe t'il si je mets un seul égal ? Le compilateur ne dit rien ?
Eh bien, avec un seul égal, la variable va être modifiée pour contenir le nombre auquel vous l'affectez. Après quoi, cette nouvelle valeur sera comparée à zéro (comme dans «if(variable)»). Ce n'est pas du tout ce que vous voulez, mais en C, c'est parfaitement légal, donc le compilateur ne met pas d'erreur (enfin, s'il est perspicace, il vous sortira tout de même un warning).

L'opérateur ==, lui, compare la variable à la valeur. C'est cela que nous recherchons.

Si vous avez peur de vous tromper, utilisez cette astuce :
if(18 == variable){

En effet, ce code est tout aussi correct (comparer 18 à variable revient au même que de comparer variable à 18), mais, si vous vous trompez, vous aurez une erreur de votre compilateur :
if(18 = variable){ /*ERREUR */

En effet, ce code tente de mettre variable dans 18, ce qui n'a aucun sens car 18 est un nombre. Le compilateur vous le signalera et refusera de compiler. Ainsi, plus de risque d'erreur inaperçue.

Avec la participation d'Yno et de scriptoff
  • Partager sur Facebook
  • Partager sur Twitter
J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
17 juin 2007 à 15:54:28

[6][2] Est-ce que j'ai le droit de faire if( variable == 1 || 2 || 3) ?

Hum... On rejoint un peu la question N°[6][1]. En gros, vous pouvez, mais il ne se passera pas ce à quoi vous vous attendez.

Petit rappel : le programme convertit toutes les conditions qu'il rencontre en nombres : 0 si la condition est fausse, une autre valeur sinon. Vous pouvez le vérifier :

#include <stdio.h>

int main()
{
    int cond = ( 1+1 == 2 );
    printf("1+1 == 2 -> %d \n", cond);

    int cond2 = ( cond == 0 );
    printf("%d == 0 -> %d", cond, cond2);

    return 0;
}


Donnera un truc du style :

1+1 == 2 -> 1

1 == 0 -> 0


Ainsi, dans un if(), le programme rentre dans le bloc {} du if si le nombre obtenu après conversion est différent de 0. Ce qui signifie qu'il est possible d'écrire :

{
    if(1)
    {
        /* Code toujours execute */
    }

    if(0)
    {
        /* Code jamais execute */
    }
}


Vous pouvez d'ailleurs remplacer 1 par n'importe quelle valeur différente de 0. Bon. Maintenant, observons ce code :

if(variable == 1 || 2 || 3)


Admettons que variable contienne 1. La condition est vraie. Elle est alors transformée comme ceci :

if( 1 || 2 || 3)


Vu qu'on utilise l'opérateur ||, soit "ou bien", il suffit que l'un de ces trois nombres soit différent de zéro pour que le bloc soit exécuté. comme 2 et 3 ne changent pas, c'est toujours le cas ! Donc cette condition sera toujours vraie, quelque soit la valeur de «variable». En fait, «2» et «3» sont évaluées comme des conditions séparées, et comme ce sont des chiffres différents de 0, ils sont toujours vrais.

Du coup, on est obligés de faire :

if(variable == 1 || variable == 2 || variable == 3)
/* Remplacable par : */
if( variable >= 1 && variable <= 3)


Encore une fois, ici, le fait d'écrire cette mauvaise condition veut dire quelque chose en C, donc le compilateur ne se plaindra pas (ou il vous donnera un warning au pire).
  • Partager sur Facebook
  • Partager sur Twitter
J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
18 juin 2007 à 9:24:25


Tient, j'ai quelque chose d'intéressant:
@ edit >> ( :-° ), ah oui, j'utilise le mot 'case' pour donner une image, je sais que ce n'est pas très correct, mais bon...

Si vous avez un buffer (char []) qui contient un nombre par exemple en 'case' 12 (donc buffer[12] = LeNombreQueJeVeuxObtenirDansUnInt).
Vous allez donc devoir passer buffer à sscanf() ; Ok ?
Alors, vous vous dites, je dois faire:
  1. char buffer[64] = {0};
  2. int MonInt = 0;
  3. fgets(...buffer...); /* Maintenant (on va dire) notre buffer contient notre nombre en 'case' 12 */
  4. /* Puis, on doit faire: */
  5. char temp[2] = {buffer[12], 0};
  6. /* On doit créer une chaine ne contenant que le nombre à passer à sscanf(), on ne peut pas lui passer les 11 caractères avant le nombre... */
  7. if(sscanf(temp, "%d", &MonInt) != 1) puts("erreur...!");
  8. /*  ...  */


C'est énervant de devoir créer une chaine juste pour sscanf() non ?
(oui, rappelez vous, les programmeurs sont fénéants :p )

Et ben, voila le truc:
  1. sscanf((char []) {buffer[12], 0}, "%d", &MonInt);

Le compilo va créer une chaine, donc, pour lui ça ne change rien, mais pour nous, c'est vachement plus pratique :)

P.S. Il me semble qu'on peut aussi modifier l'argument 2 de sscanf() pour qu'il ne prenne que à partir du 12eme caractère mais bon, je préfère mon truc.
  • Partager sur Facebook
  • Partager sur Twitter
18 juin 2007 à 11:11:16

Je rappelle la différence entre les chiffres et les nombres :
http://fr.wikipedia.org/wiki/Chiffre

Citation : Zulon

Ou pas: si c'est juste un chiffre, c'est atoi(buffer[12]);


Soyez précis svp, car pour les chiffres, ceci est portable (merci candide) :
  1. int chiffre = buf[<id>] - '0';

De plus, atoi() attend un pointeur sur char, par un char, et pour finir elle est paraît-il dépréciée (elle et ses copines ato*).
http://www.siteduzero.com/forum-83-125906-1303181.html#r1303181

Et pour les nombres, en supposant que nous en ayons un qui commence en "case" 12 :
  1. long number = strtol(&buf[12], NULL, 0);
  • Partager sur Facebook
  • Partager sur Twitter
23 juillet 2007 à 1:02:28

[8][5] Exécuter une ou plusieurs fonction a la fermeture d'un programme :

Voila son prototype :

#include <stdlib.h>
int atexit(void (*fonction) (void ));


Effrayant hein ? o_O

Mais non c'est tout bête. Cette fonction permet d'exécuter une ou plusieurs fonction a la fin d'un programme. Elle sont lancées par exit dans l'ordre inverse de leur positionnement par atexit.

Exemple :

void coucou()
{

      printf("coucou\n");

}

void bonjour()
{

      printf("On dit bonjour malpoli!\n");

}

int main()
{
      atexit(bonjour);
      atexit(coucou);

      exit(0);
}


Bien sûr il faut rajouter des choses, mais s'est juste pour vous montrer :

coucou

On dit bonjour malpoli!


Il me semble que le nombre de fonction appelable grâce a atexit est limité, à 20 (à vérifier).
  • Partager sur Facebook
  • Partager sur Twitter
23 juillet 2007 à 9:21:43

Citation

POSIX.1-2001 nécessite que l’implémentation suive au moins ATEXIT_MAX
(32) pour que de telles fonctions soient enregistrées. La limite
actuelle de l’implémentation peut être obtenue avec sysconf(3).

  • Partager sur Facebook
  • Partager sur Twitter
7 octobre 2007 à 22:13:04

Pas mal cette nouvelle mouture de la FAQ.

Citation : Yno

pour les chiffres, il me semble que ceci est portable :

  1. int chiffre = buf[<id>] - '0';

Oui, ça l'est, cf. le standard :

Citation : Norme C99


5.2.1 Character sets
[...]
In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.



Comme l'a observé psychoh13 sur le forum, ici, pour les encodages ASCII ou EBCDIC, c'est même vrai pour les 16 chiffres hexadécimaux.

EDIT
Lien exact vers la réponse de psychoh13
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
22 novembre 2007 à 1:18:07

Citation : PianoPâriss


Tient, j'ai quelque chose d'intéressant:
@ edit >> ( :-° ), ah oui, j'utilise le mot 'case' pour donner une image, je sais que ce n'est pas très correct, mais bon...

Si vous avez un buffer (char []) qui contient un nombre par exemple en 'case' 12 (donc buffer[12] = LeNombreQueJeVeuxObtenirDansUnInt).
Vous allez donc devoir passer buffer à sscanf() ; Ok ?
Alors, vous vous dites, je dois faire:

  1. char buffer[64] = {0};
  2. int MonInt = 0;
  3. fgets(...buffer...); /* Maintenant (on va dire) notre buffer contient notre nombre en 'case' 12 */
  4. /* Puis, on doit faire: */
  5. char temp[2] = {buffer[12], 0};
  6. /* On doit créer une chaine ne contenant que le nombre à passer à sscanf(), on ne peut pas lui passer les 11 caractères avant le nombre... */
  7. if(sscanf(temp, "%d", &MonInt) != 1) puts("erreur...!");
  8. /*  ...  */



C'est énervant de devoir créer une chaine juste pour sscanf() non ?
(oui, rappelez vous, les programmeurs sont fénéants :p )

Et ben, voila le truc:

  1. sscanf((char []) {buffer[12], 0}, "%d", &MonInt);


Le compilo va créer une chaine, donc, pour lui ça ne change rien, mais pour nous, c'est vachement plus pratique :)

P.S. Il me semble qu'on peut aussi modifier l'argument 2 de sscanf() pour qu'il ne prenne que à partir du 12eme caractère mais bon, je préfère mon truc.


Attention, les litéraux composés sont une nouveauté de C99, tous les compilateurs ne l'implémentent pas.
  • Partager sur Facebook
  • Partager sur Twitter
16 février 2008 à 18:45:45

Citation : Kevin Leonhart

[6][1] Comment créer un MMORPG ?

  • [...]
  • Sais-je programmer correctement dans le langage que j'ai choisit ?
  • Ais-je de bonnes connaissances d'un moteur 3D ? physique ?
  • Ais-je une expérience des gros projets en programmation ?
  • Ais-je une bonne expérience de la programmation réseaux ?
  • Pourquoi diantre faut il plusieurs années à des équipes de professionnels payés qui ne font que ça de leurs journées pour mettre au point un MMORPG ?




Je pense que ce n'est pas tout à fait exact, je vais reprendre point par point.
  • Oui il faut savoir programmer dans le langage informatique qu'on a choisi
  • Non les MMORPG en 2D existent, certains ont un physique plutôt austère même voir totalement repoussant!
  • Oui et non. La création d'un MMORPG est un TRES gros projet par rapport à la majorité des projets qu'on trouve ici mais non ce n'est pas aussi compliqué (tout est très relatif) s'il s'agit d'un MMORPG assez basique, il peut même être assez joli (en connaissant 2/3 graphistes excellents avec pas mal de temps devant eux
  • Rien à redire sur le besoin d'expérience en programmation réseau
  • Les MMORPG ne sont pas tous fait par 800 personnes d'une société bourrée de fric.
    Un exemple avec la page des contributeurs (dev mais aussi testeurs, packaqeurs...) de The Mana World : http://sourceforge.net/project/memberlist.php?group_id=106790

En gros je dirais que MMORPG!=WoW
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
14 avril 2008 à 14:58:09

Comment récupérer un fichier se trouvant sur un serveur distant ?

C'est relativement compliqué, car un simple fopen() ne fonctionne pas.
Vous devez employer l'API Socket de votre système, puis dialoguer avec le serveur distant dans le protocole adéquat.
  • Partager sur Facebook
  • Partager sur Twitter
18 octobre 2008 à 16:49:58

[2][6] Comment afficher correctement et simplement les caractères spéciaux dans la console ?

Les caractères spéciaux tels les accentués ne sont pas affichables "simplement" comme on voudrait le faire :
printf("é");

Avec le précédent code, on affiche 'Image utilisateur', or on aimerait afficher 'é'.
Pour cela, l'une des meilleurs solutions consiste à passer par la valeur hexadécimale du caractère (cf la table ASCII) précédé de '\x'. le caractère spécial 'é' vaut 82 en hexa, donc pour l'afficher correctement, il faut corriger le code et compiler avec :
printf("\x82")

On peut utiliser cette méthode pour tous les caractères, même les plus tordus comme le bip sonore (hex : 7).
  • Partager sur Facebook
  • Partager sur Twitter
29 janvier 2009 à 19:39:55

Euh, crys', ton truc c'est bien gentil mais ça complique le code pour obtenir un résultat qui n'est de toute façon pas portable ...
Ta "solution" ne résout en aucun cas le fameux problème des caractères spéciaux de façon satisfaisante ...
Je crois que Vista affiche bien les accents maintenant (à confirmer svp) donc ça règlera le problème à terme.
  • Partager sur Facebook
  • Partager sur Twitter
26 juillet 2009 à 13:34:12

[1][7] Quels sont les différentes séquences d'échappement avec printf et quels sont les différents formats à utiliser avec printf et scanf ?

Les fonctions printf() et scanf() (et dérivées*) de la bibliothèque d'entrée/sortie standard (stdio.h) sont dites fonctions d'entrées et sorties formatées. En effet, il existe pour ces fonctions un certain nombre de formats d'entrée/sortie pour les expressions fournies en paramètres. Par ailleurs, il existe également pour ces fonctions, comme pour d'autres**, un certain nombre de carractères spéciaux encore appelés séquences d'échappement.

* : J'entend par "dérivées", les fonctions sprintf () , sscanf () , fprintf () , fscanf () , ...
** : Il existe d'autres fonctions d'entrée/sortie standard (non-formatées cette fois) à l'exemple de getchar() , putchar() , ...


Dans cette rubrique, nous allons faire une liste des principaux carractères d'échappement et formats utilisés par ces fonctions.

Les séquences d'échappement (caractères spéciaux) avec printf :



Séquence d'échappement Effet
\n saut de ligne
\t tabulation horizontale
\v tabulation verticale
\b placement du curseur
\r retour chariot (carriage return)
\f saut de page
\a signal sonore
\\ antislash
\" double quote (guillemet)
%% Caractère "%"


Les formats de sortie avec printf :



Format Type de donnée
%d, %i nombre entier décimal
%u nombre entier non signé (unsigned)
%o nombre entier octal
%x nombre entier hexadécimal (minuscule)
%X nombre entier hexadécimal (majuscule)
%c caractère ASCII (type char)
%f nombre à virgule flottante
%e, %E nombre à virgule flottante au format exponentiel
%g, %G nombre au format %f ou %e (lorsque l'exposant est inférieur à -4)
%a, %A nombre de type double affiché en notation hexadécimale (avec les lettres abcdef en minuscules pour %a et en majuscules pour %A)
%s chaîne de caractères
%p pointeur
%n pointeur (nombre de caractères déjà donnés)


Remarque :

Selon la man page de printf :

- Les formats %d à %X concernent les variables de type int. Pour les variables de type short, il faut ajouter un h après le % (exemple : %hd) et pour les variables de type long, il faut ajouter, il faut ajouter un l après le % (exemple : %ld).

- Les formats %f à %LG concernent les variables de type float. Pour les variables de type double, il faut ajouter un l après le % (exemple : %lf).

Il se peut toutefois que vous ayez un Warning du genre "ISO C90 does not support the `%lf' printf format". En effet, les formats %lf (nombre à virgule de type double), %hhd (char signé) et %hhu (char non signé) n'existent qu'en C99.

Les formats de saisie avec scanf :



Format Type de donnée
%d entier décimal de type int
%i nombre entier de type int
%hd entier décimal de type short
%ld entier décimal de type long
%u entier décimal de type int non signé (unsigned)
%hu entier décimal de type short non signé (unsigned short)
%lu entier décimal de type long non signé (unsigned long)
%o entier octal de type int
%ho entier octal de type short
%lo entier octal de type long
%x entier hexadécimal de type int
%hx entier hexadécimal de type short
%lx entier héxadécimal de type long
%c caractère ASCII (type char)
%f nombre à virgule flottante de type float
%lf nombre à virgule flottante de type double
%e, %E nombre à virgule flottante au format exponentiel de type float
%le, %LE nombre à virgule flottante au format exponentiel de type double
%g, %G nombre à virgule flottante au format décimal ou exponentiel (lorsque l'exposant est inférieur à -4) de type float
%lg, %LG nombre à virgule flottante au format décimal ou exponentiel (lorsque l'éxposant est inferieur à -4) de type double
%s chaîne de caractères
%p pointeur
%n aucune donnée utilisateur (montre le nombre de caractères déjà lus)
  • Partager sur Facebook
  • Partager sur Twitter
24 août 2009 à 10:50:41

Lorsque je compile sous Code::blocks, ça me sort "Nothing to be done". Pourquoi ?

Tout simplement parce que le code::blocks n'a pas de compilateur configuré. Pour cela, il faut le faire manuellement :
Setting => Compiler and Debugger => Toolchain executable => Auto-detect.
Ça devrais marcher maintenant :)

Sinon, dans "Settings=>Compiler and Debugger=>Toolchain executables" (de votre logiciel code::Blocks), vous pouvez régler là où est le dossier "MinGW" à l'origine, c'est à dire : "C:\(Dossier d'instalation)\CodeBlocks\MinGW"

Avec la participation de Titi29.

Voir aussi Cette réponse.
  • Partager sur Facebook
  • Partager sur Twitter
19 février 2010 à 1:30:37

[5][7] Comment ajouter une bibliothèque à son projet CodeBlocks ?

Télécharger les archives contenant devel ou dev dans leur nom.
Décompresser l'archive quelque part. (de préférence, on évite un répertoire dont le chemin contient des espaces)

Dans codeblocks, projet->build options->search directories, rajouter les dossiers et sous dossiers de lib dans l'onglet linker, et les dossiers et sous-dossiers de include dans l'onglet compiler.

Dans codeblocks projet->build options->linker settings->link librairy, mettre tous les ".lib", ".a" ou ".la" du repertoire lib.

Une fois cela fait, aller dans file->save project as user templates. Pour ne pas avoir à refaire les étapes précédentes à chaque nouveau projet.



Note: Si vous ne disposez que des sources pour cette bibliothèque, vous pouvez toujours essayer les compiler en utilisant MSys. ;)
  • Partager sur Facebook
  • Partager sur Twitter
- Il y a un chemin vers chaque sommet, même le plus haut -
20 février 2010 à 0:22:59

[6][5] Quand je veux compiler mon programme, codeblocks me dit

Citation

"CCC - Debug" uses an invalid compiler. Skipping...
Nothing to be done.



Sous Windows :

Il peut y avoir deux solutions à ce problème:
-Vous n'avez pas téléchargé la version de codeblocks contenant MinGW.
Dans ce cas, vous pouvez la télécharger ici, en prenant la version codeblocks-X.XXmingw-setup.exe, où X.XX représente le numéro de version.

-Le chemin vers MinGW est incorect.
Ouvrez codeblocks, allez dans "settings->compiler&debugger->toolchain executable". cliquez sur parcourir (les "..."), et saisissez le repertoire "MinGW" dans votre installation. Si vous avez installé codeblocks avec MinGW, celui-ci se trouve dans le répertoire de codeblocks, puis cliquez sur OK.

Sous Linux :

- Vérifiez que vous avez bien installé gcc depuis votre gestionnaire de paquets. Par exemple, sous Debian et Ubuntu, le paquet à installer est build-essential.
  • Partager sur Facebook
  • Partager sur Twitter
- Il y a un chemin vers chaque sommet, même le plus haut -
21 février 2010 à 21:21:22

[7][4] Comment créer des programmes qui communiquent entre eux ou sur le réseau ?

On utilise pour cela ce que l'on appelle des sockets. Il vous faut donc vous documenter sur les sockets, par exemple avec ce tutorial du site.

Si les programmes sont sur la même machine, on peut également utiliser un fichier ou bien des pipes (tuyaux).
  • Partager sur Facebook
  • Partager sur Twitter
J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
21 février 2010 à 21:26:01

[7][5] Comment créer un virus, trojan, keylogger, launcher ?

Nous ne vous aiderons pas à créer de genre de programmes. Il est inutile d'arguer que c'est pour un cadre privé, que c'est légal, etc... C'est niet. Vous trouverez toutes les informations qu'il vous faut ailleurs.
  • Partager sur Facebook
  • Partager sur Twitter
J'ai déménagé sur Zeste de savoir — Ex-manager des modérateurs.
7 mars 2010 à 11:11:01

[8][7] Comment créer un tableau 2D dynamique ?

Créer un 'vrai' tableau 2D avec l'allocation dynamique n'est pas possible, en revanche il est possible de créer un tableau de pointeurs qui se comportera comme un tableau 2D, à l'exception près que les éléments de ce tableau de seront pas contigüs (ou très peu de chances).

#include <stdlib.h>

#define N_1ERE_DIM 5
#define N_2NDE_DIM 10

int main(void) {
  int i;
  char ** tab = NULL;
  
  /* Allocation de la 'première' dimension (le tableau de pointeurs). */
  if ((tab = malloc(N_1ERE_DIM * sizeof *tab)) == NULL)
    exit(EXIT_FAILURE);
  /* Vous pouvez aussi faire malloc(N_1ERE_DIM * sizeof(char*)) */
  
  /* Allocation de la 'seconde' dimension. */
  for (i = 0; i < N_1ERE_DIM; i++)
    if ((tab[i] = malloc(N_2NDE_DIM * sizeof *tab[i])) == NULL)
      exit(EXIT_FAILURE);
  /* Vous pouvez aussi faire sizeof(char) (notez l'étoile en moins). */
  
  
  /* Pour libérer on fait le chemin inverse. */
  for (i = 0; i < N_1ERE_DIM; i++) {
    free(tab[i]);
    tab[i] = NULL;
  }
  free(tab);
  tab = NULL;
  
  return EXIT_SUCCESS;
}

Un des avantages de l'allocation dynamique, c'est qu'il permet de ne pas avoir la même taille de toutes les 'secondes dimensions'. Pour ce faire il suffit de modifier, dans le code ci-dessus, le malloc dans la boucle et de mettre une valeur différente.

Il y a une autre manière de faire, moins gourmande en allocations. Allez voir ici : http://www.siteduzero.com/forum-83-125 [...] html#r4838547
  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2010 à 21:08:22

[3][8] Quelle est la différence entre les deux déclarations suivantes char * chaine et char chaine[] ?

A première vue ces 2 déclarations sont identiques mais elles ne le sont pas. ;)
Examinons la déclaration de chacune.

La déclaration char * chaine déclare un pointeur sur une chaîne de caractères non modifiable. C'est-à-dire que si vous essayez de modifier le contenu de cette chaîne vous vous retrouverez avec un joli SEGFAULT !
Pour lever toute ambiguïté je conseille en général de déclarer la chaîne comme constante, ainsi le compilateur vous dira que c'est illicite et le programme ne risquera pas de planter à cause de ça. ;)

char const * chaine = "chaine de caractere non modifiable !";

Il est à noter que comme c'est un pointeur on peut tout à fait le faire pointer sur autre chose, mais attention à bien savoir ce que vous faîtes. Je conseille généralement (encore !) de déclarer ce pointeur comme constant char const * const chaine = "string";.

La déclaration char chaine[] déclare un tableau de char, il a donc toutes les propriétés des tableaux et des chaînes de caractères.

Si vous voulez plus d'explications, allez voir ce post.

Attention cependant : lorsqu'il s'agit des paramètres d'une fonction, ces deux formes sont équivalentes ! Ainsi,
int strcmp(char *a, char *b);
int strcmp(char a[], char b[]);

sont deux prototypes identiques.
Ce tutoriel vous explique le pourquoi du comment. :)
  • Partager sur Facebook
  • Partager sur Twitter
21 mars 2010 à 14:43:07

[8][8] Qu'est-ce que size_t, et quand l'utiliser ?


'size_t' est un type d'entier non signé (c'est-à-dire positif) et est le type du résultat provenant de l'opérateur sizeof. Il est déclaré le plus souvent comme ceci :
typedef unsigned int size_t

mais peut aussi être un unsigned long, unsigned short, etc.

'size_t' est défini dans le fichier d'en tête stddef.h,lui même inclut dans les fichiers stdio.h, stdlib.h, et string.h.

'size_t' convient pour tout ce qui n'est pas négatif, mais est surtout utilisé pour définir la taille de chaînes ou d'éléments. Il convient parfaitement à la valeur que renvoie sizeof, aux indices de tableaux, ou encore pour définir la taille d'un élément lors d'une allocation dynamique :

/* Utilisation du size_t comme paramètre de taille lors d'une malloc() : */
size_t tailleChaine = 500;

maChaine = malloc(tailleChaine);

/* Utilisation du size_t pour stocker le nombre de membres d'une chaine : */
size_t longChaine = 0;

longChaine = strlen(maChaine);

/* Utilisation du size_t comme indice de tableau : */
size_t i = 0;

maChaine[i] = 0;

/* Utilisation du size_t pour recueillir la valeur donnée par sizeof() :*/
size_t tailleChaine = 0;

tailleChaine = sizeof(maChaine);
  • Partager sur Facebook
  • Partager sur Twitter