2009-04-21 9 views
2

J'ai besoin d'écrire des données dans un fichier binaire en utilisant les fonctions d'E/S de C. Le code suivant provoque une exception d'exécution:Problème lors de l'écriture d'un fichier binaire dans C


#include "stdio.h" 

int main(int argc,char* argv[]) { 
    FILE *fp = fopen("path_to_file.bin","wb"); 
    if(fp == NULL) { 
     printf("error creating file"); 
     return -1; 
    } 
    int val = 4; 
    fwrite((const void*)val,sizeof(int),1,fp); 
    fclose(fp); 
    return 0; 
} 

Le code meurt à l'écriture. Pouvez-vous repérer ce que je fais mal? Apparemment, j'essaie d'accéder aux données à 0x0000004 ou quelque chose comme ça.

Merci!

Répondre

14
fwrite((const void*)val,sizeof(int),1,fp); 

devrait être:

fwrite((const void*) & val,sizeof(int),1,fp); 

BTW, si vous n'utilisez pas le casting, vous obtiendrez un message d'erreur sensible. Les casts ont tendance à être utilisés par les programmeurs C (et C++) beaucoup plus souvent qu'ils ne devraient l'être - une bonne règle empirique est "si elle a besoin d'une distribution, c'est probablement faux".

+0

+1 pour votre règle générale. –

+0

+ un autre 1 pour cette règle. Je l'ai sur une note autocollante sur mon moniteur. – Greg

5

Ajout à la réponse de Neil: cela fonctionne lorsque vous lisez et écrivez le fichier sur la même plate-forme. Les choses peuvent devenir bizarres si vous lisez/écrivez sur des plates-formes avec une endianness différente.

+0

Non seulement l'endianness, aussi la taille peut varier. – quinmars

+0

C n'est pas multi-plateforme, dans l'écriture/lecture de fichiers vous devez faire une implémentation pour chaque plate-forme la plupart du temps, différents marqueurs de fin de ligne et des choses comme ça deviennent un cauchemar pour l'écriture/lecture de fichiers sujet de toute façon: P) –

23

Je pense que la réponse de Neil peut être améliorée. Je me rends compte que c'est déjà accepté, donc c'est juste pour montrer du contraste (c'est pourquoi je n'ai pas seulement édité le sien).

fwrite(&val, sizeof val, 1, fp); 

Deux améliorations:

  • Pas coulée de pointeur, car il est pas nécessaire en C et peut cacher des erreurs. Utilisez sizeof directement sur l'objet, puisque c'est ce que vous passez un pointeur. Cela a beaucoup de sens pour moi, et c'est plus sûr que de se répéter et d'utiliser le nom du type.
+1

+1 Bons points, les deux. Morale de l'histoire: préférez les petits moulages et utilisez judicieusement la taille. – dirkgently

+1

Pouvez-vous expliquer pourquoi la distribution n'est pas nécessaire? Je ne suis pas un programmeur C ... et je voudrais comprendre autant que possible de sa "magie". – Geo

+7

fwrite() attend un void * comme premier argument. N'importe quel type de pointeur peut être utilisé où un void * est attendu sans cast. void * dit effectivement "J'ai besoin d'un pointeur, peu importe le type auquel il renvoie". – Ferruccio

0
#include "stdio.h" 

int main(int argc,char* argv[]) { 
    FILE *fp = fopen("path_to_file.bin","wb"); 
    if(fp == NULL) { 
     printf("error creating file"); 
     return -1; 
    } 
    int val = 4; 
    fwrite((const void*)val,sizeof(int),1,fp); 

Vous devez fournir une adresse pas lui-même entière.

Additionaly vous ne devriez pas utiliser l'entier de telle manière:

  1. Il peut différer endianess sur des ordinateurs différents (comme mentionné)
  2. Il peut varier en taille. Sur les ordinateurs vraiment vieux, il peut y avoir 1 ou 2 octets. Sur le plus moderne, il sera de 4, mais il peut également être 8 (certains ordinateurs 64 bits). Sur certaines architectures étranges, il peut même s'agir de 36 bits. int32_t val = 4; fwrite((const void *)val, 4, 1, fp) devrait résoudre le problème.

Vous pensez peut-être que votre logiciel n'aura jamais besoin d'être porté. Bien - beaucoup de concepteurs (logiciels et matériels) ont fait des suppositions similaires. Parfois, il est trop coûteux de ne pas les fabriquer - mais dans ce cas, il ne s'agit que de quelques vérifications supplémentaires.

fclose(fp); 
    return 0; 
} 
0

J'ai également fait face à ce genre de problème. Donc c'est ma solution.

fwrite(val, sizeof(val[0], sizeof(val)/sizeof(val[0]), fp);

0

Apparemment, je suis, en essayant d'accéder aux données à 0x0000004 ou quelque chose comme ça.

int val = 4 

Il y a la question. fwrite est conçu pour fonctionner avec des chaînes, et en tant que telle, sa première entrée est un pointeur, l'emplacement d'une chaîne en mémoire. Vous passez la valeur de val directement (4) plutôt que l'adresse de val à fwrite; cependant, la mémoire à 0x00000004 n'est pas une mémoire de programme valide et donc une erreur est donnée.

Pour résoudre ce problème, changer ceci:

fwrite((const void*)val,sizeof(int),1,fp); 

Dans ceci:

fwrite((const void*)&val, sizeof(int), 1, fp); 

L'opérateur "&" indique l'emplacement de val. Ce serait une adresse valide en mémoire.

Questions connexes