2010-03-04 7 views
3

En C/C++, il existe une fonction 'write() qui me permet d'écrire sur un fichier ou un socket, je passe juste le descripteur de fichier en conséquence). Et il y a un fprintf() qui me permet de faire fprintf (myFile, "hello% d", name); mais cela ne fonctionne que pour le fichier.Une fonction combinée pour fprintf et écrire en c/C++

Y a-t-il des API qui me permettent de faire les deux? En d'autres termes, est-ce que je peux faire le formatage d'impression et pouvoir passer de l'écriture au fichier ou à la socket?

Merci.

Répondre

3

Vous pouvez utiliser sprintf ou snprintf pour imprimer dans un tampon char *, puis utiliser write. Pour obtenir un descripteur de fichier à partir d'une variable FILE *, vous pouvez utiliser fileno. Il n'y a pas de manière portable de passer d'un descripteur de fichier à un FILE *, cependant: vous pouvez utiliser de façon portative fdopen à associer un à un FILE * avec un descripteur de fichier valide.

En outre, la dernière norme POSIX spécifie dprintf, mais la GNU libc dprintf page man a ceci à dire:

Ces fonctions sont des extensions GNU, non en C ou POSIX. Clairement, les noms ont été mal choisis. De nombreux systèmes (comme MacOS) ont incompatibles les fonctions appelées dprintf(), généralement une version de débogage de printf(), peut-être avec un prototype comme

void dprintf (int level, const char *format, ...); 

où le premier paramètre est un niveau de débogage (et la sortie est à stderr). En outre, dprintf() (ou DPRINTF) est également un nom de macro populaire pour un débogage printf. Donc, probablement, il est préférable d'éviter cette fonction dans les programmes destinés à être portables.

Bien sûr, la page de manuel libc est pas mis à jour avec la dernière norme à l'esprit, mais vous devez toujours être prudent avec l'utilisation dprintf, puisque vous pourriez obtenir quelque chose que vous ne voulez pas. :-)

+0

Problème avec 'snprintf' (je prétends que vous n'avez pas mentionné' sprintf') c'est qu'il est difficile de déterminer la taille du tampon sans que chaque 'my_printf' fasse potentiellement un' malloc 'et' free'. A moins que vous ne sachiez mieux que 1) essayez 'snprintf' avec un tampon de taille arbitraire sur la pile, 2) si' snprintf' renvoie un nombre plus petit que le buffer, alors 'write' le buffer et retournez, sinon 3)' malloc' un tampon au moins de cette taille, 'snprintf' dedans,' write', puis 'free' et retour. –

+0

@Mike: 'snprintf()' avec le tampon 'NULL' et la taille 0 vous donne la taille requise en C99. Mais cela signifie que 'snprintf' est appelé deux fois pour chaque tampon. J'aime beaucoup dprintf, mais il se peut qu'il ne soit pas disponible. 'fdopen' est sympa, mais je suis à peu près sûr qu'il faut créer deux 'FICHIER *' si on veut lire et écrire en utilisant cette approche. Merci pour votre commentaire! –

+0

Il est intéressant qu'ils disent que MacOS a un 'dprintf 'incompatible, parce que' man dprintf' sur ma boîte Mac OS X 10.6 donne 'Aucune entrée manuelle pour dprintf'. Je n'avais jamais entendu parler de 'dprintf' avant, de toute façon. –

4

Bien sûr: il suffit d'utiliser fdopen sur le socket pour créer un flux FILE*, et utiliser correctement fprintf.

+4

sur les systèmes GNU, il y a aussi 'dprintf()' (voir par exemple http://linux.die.net/man/3/dprintf) – Christoph

+2

Un problème à propos de l'utilisation de fdopen est que vous devez utiliser fclose (ou vous risquez de perdre des ressources) et vous ne pouvez pas utiliser close (ou vous doublez le descripteur). Si votre code n'est pas responsable de la durée de vie du descripteur, vous ne devez pas utiliser fdopen. –

4

En C, sur les machines Posix-ish (que vous devez avoir à l'aide de 'write()'), vous pouvez utiliser:

  • fdopen() pour créer un flux de fichier à partir d'un descripteur de fichier.
  • fileno() pour obtenir un descripteur de fichier à partir d'un flux de fichier.

Vous devez faire attention à vider le flux de fichiers à des moments appropriés avant d'utiliser le descripteur de fichier correspondant.

+3

Un problème à propos de l'utilisation de fdopen est que vous devez utiliser fclose (ou que vous pouvez perdre des ressources) et vous ne pouvez pas utiliser close (ou vous doublez le descripteur). Si votre code n'est pas responsable de la durée de vie du descripteur, vous ne devez pas utiliser fdopen. –

0

Vous pouvez faire quelque chose comme ça, peut-être:

#include <stdarg.h> 

int fdprintf(int fd, const char* fmt, ...) { 
    char buffer[4096] = {0}; 
    int cc; 
    va_list args; 
    va_start(args, fmt); 
    if ((cc = vsnprintf(buffer, 4096, fmt, args)) > 0) { 
    write(fd, buffer, cc); 
    } 
    va_end(args); 
    return cc; 
} 
+0

cela ne fonctionnera pas si la chaîne résultante est plus de 4096 octets. vous pouvez déterminer la taille de tampon nécessaire par int len ​​= _vscprintf (fmt, args) +1; dans Visual C++ – uray

+0

@uray: avec un vsnprintf() conforme à la norme, vous pouvez utiliser: 'len = vsnprintf (0, 0, fmt, args) + 1;' –

+0

msdn dit http://msdn.microsoft.com/ En-us/library/1kt27hek% 28VS.80% 29.aspx ... "Si le tampon ou le format est NULL, ou si count est inférieur ou égal à zéro, ces fonctions appellent le gestionnaire de paramètres invalide, comme décrit dans la section Validation des paramètres Si l'exécution est autorisée à continuer, ces fonctions renvoient -1 et donnent errno à EINVAL "est-ce conforme à la norme? – uray

0

généralisante réponse tusbar, et de le faire fonctionner avec le studio visuel, vous pouvez essayer les codes suivants: `

int fdprintf(int fd, const char* fmt, ...) { 
    int cc; 
    va_list args; 
    va_start(args, fmt); 
    int len = _vscprintf(fmt,args) + 1; 
    char* buffer = new char[len]; 
    buffer[len] = 0; 
    if ((cc = vsprintf_s(buffer, len-1, fmt, args)) > 0) { 
     write(fd, buffer, cc); 
    } 
    va_end(args); 
    delete[] buffer; 
    return cc; 
} 

`

Questions connexes