PDA

Visualizza la versione completa : [ANSI C] compilatore per win OK, per Linux NO


andr3a
16-03-2005, 17:48
dagli studi fatti dal mi oprof di programmazione, dagli studi fatti personalmente sulla rete, dopo non essere stato ammesso ad un esame ho riscritto da zero il programma ... risultato ??

peggio di prima ... secondo il professore ...

ora vorrei chiedervi, gentilmente, di testare questo programma su una piattaforma Linux perche' su Windows va perfetto ... oltretutto vorrei chiedere ad i piu' esperti una valutazione reale sul codice da me scritto, grazie

exam.c


/************************************************** ******************************/
/* CPRO - Computer Programming */
/* __________________________________________________ __________________________ */
/* programma per creare una copia di un file di testo su un altro file con */
/* l' aggiunta di un header e con le linee ordinate in ordine crescente */
/* ---------------------------------------------------------------------------- */
/* @autore: Andrea Giammarchi */
/* @data: 17/02/2005 */
/* @ambiente: Windows 2000 SP4 */
/* @programma: Dev C++ V 4.9.9.1 */
/* @compilatore: GCC 3.3.1 */
/************************************************** ******************************/


/*****************************/
/* inclusione delle librerie */
/*****************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


/*****************************************/
/* definizione delle costanti simboliche */
/*****************************************/
#define OUTPUT_HEADER_PREFIX_SUFFIX "**********" /* informazioni suffisso e prefisso
per l' header del nuovo file */
#define AUTO_SUFFIX ".lis" /* suffisso predefinito del file creato
( usato qualora l'utente non indichi
il nome del nuovo file )*/


/************************************************** ***********/
/* descrizione del tipo di dato boolean_t : */
/* Questo dato indica una espressione di tipo booleana */
/* utilizzata nel programma per verificare se calloc */
/* e' stato utilizzato al fine di liberare la memoria */
/* occupata dalla funzione calloc */
/************************************************** ***********/
typedef enum {
falso,
vero
} boolean_t;


/************************************************** **********/
/* descrizione della funzione getFileOnExists : */
/* funzione ricorsiva per verificare il file scritto */
/* o indicato dall' utente. */
/* Se il file non e' presente si richiama dopo aver */
/* mandato un messaggio di informazione file mancante */
/* per riverificare se il nuovo file, digitato */
/* dall' utente, e' esistente cosi' da ritornare il */
/* puntatore al file aperto in sola lettura */
/************************************************** **********/
FILE *getFileOnExists(
char *input_source_file /* input, file da leggere */
);


/*************************************/
/* definizione della funzione main */
/*************************************/
int main(int argv, char **argc)
{

/* dichiarazione delle variabili locali alla funzione */
FILE *source_file, /* input: file sorgente */
*destination_file; /* output: file di destinazione */
char *input_file, /* input: nome file da leggere */
*output_file; /* input: nome file da scrivere */
unsigned int a; /* i/o: utilizzata per cicli e controlli */
boolean_t used_calloc = falso; /* i/o: specifica se il programma ha usato calloc */


/* output: informazioni a video sul programma */
printf("\n################################################ #####");
printf("\n# CRPO - Computer Programming #");
printf("\n# _________________________________________________ #");
printf("\n# Questo programma crea una copia di un file di #");
printf("\n# testo aggiungendo un prefisso e, per ogni linea #");
printf("\n# del nuovo file, il corrispettivo numero di riga #");
printf("\n# seguito da uno spazio. #");
printf("\n# ------------------------------------------------- #");
printf("\n# Autore: Andrea Giammarchi #");
printf("\n# Versione: 2.0 #");
printf("\n# Data: 17/02/2005 #");
printf("\n# ------------------------------------------------- #");
printf("\n################################################ #####\n");


/* controllo: verifica i parametri passati alla funzione main. */
/* Se non viene passato alcun parametro invia un help. */
/* Se viene passato un solo parametro, crea in modo */
/* dinamico il nuovo nome file da utilizzare. */
/* Se vengono passati 2 parametri utilizza il secondo */
/* come nome per il file che verra' creato. */
switch(argv)
{
case 2:
case 3:
/* azione: assegna argc[1] alla variabile input_file */
input_file = argc[1];

/* controllo: verifica esistenza file di input e lo assegna al puntatore di tipo FILE */
source_file = getFileOnExists( input_file );

/* controllo: verifica se il secondo parametro di input sia stato scritto */
if(argc[2] != NULL)
{
/* azione: assegna tale parametro come nome file da creare */
output_file = argc[2];
}
else
{
/* azione: creo 2 variabili di tipo int utili per non */
/* richiamare strlen al prossimo ciclo for */
int len_input_file = strlen(input_file); /* lunghezza stringa input */
int len_AUTO_SUFFIX = strlen(AUTO_SUFFIX); /* lunghezza stringa suffisso */

/* azione: richiede blocchi memoria per creare l' array stringa */
/* con caratteri pari alla somma della lunghezza del */
/* nome del file da leggere piu' la lunghezza del */
/* suffisso predefinito piu' 1 carattere per terminare */
output_file = (char *) calloc(
(len_input_file + len_AUTO_SUFFIX + 1),
sizeof(char)
);

/* azione: copia carattere per carattere il nome del file da */
/* leggere per poi accodare il suffisso */
for(a = 0; a < (len_input_file + len_AUTO_SUFFIX); a++)
{
if(a < len_input_file)
{
output_file[a] = input_file[a];
}
else
{
output_file[a] = AUTO_SUFFIX[(a-len_input_file)];
}
}

/* azione: aggiunge la terminazione della stringa */
output_file[a] = '\0';

used_calloc = vero;
}

/* controllo: verifica se e' possibile aprire in modalita' scrittura */
/* il file di output */
if((destination_file = fopen(output_file, "w")))
{
/* azione: scrivo l' header all' inzio del nuovo file */
fprintf(
destination_file,
"%s%s%s",
OUTPUT_HEADER_PREFIX_SUFFIX,
output_file,
OUTPUT_HEADER_PREFIX_SUFFIX
);

/* azione: azzero a per usarla nel prossimo ciclo while */
/* creo una variabile di tipo char per leggere */
/* carattere dopo carattere il file di input */
a = 0; /* contatore linee per il nuovo output */
char content; /* lettore caratteri per l' output */

/* azione: ciclo il file di input fino alla fine */
while(!feof(source_file))
{
/* azione: assegno a content il prossimo carattere del file di input */
content = (char)fgetc(source_file);

/* controllo: verifica che content non sia la fine del file */
if(content != EOF)
{
/* controllo: verifica che content non sia un "a capo" */
if(content != '\n')
{
/* controllo: verifica che a sia a uguale a 0 */
if(a == 0) {
/* azione: scrive in output l' inizio della prima linea */
/* dopo aver incrementato a di 1 */
fprintf(destination_file,
"\n[%d] ",
++a
);
}
/* azione: scrive in output il carattere corrente */
fprintf(destination_file,
"%c",
content
);
}
else
{
/* azione: scrive in output il ritorno a capo ed aggiunge */
/* le modifiche richieste dal programma */
fprintf(destination_file,
"\n[%d] ",
++a
);
}
}
}

/* azione: flush e chiusura del file di output ( prioritario ) */
fflush(destination_file);
fclose(destination_file);

/* azione: chiusura del file di input */
fclose( source_file );

/* azione: stampa in output le informazioni di programma terminato */
printf("\nIl file \"%s\" e' stato creato con successo, arrivederci .", output_file);

/* controllo: verifica se calloc e' stato utilizzato */
if( used_calloc ) {
/* azione: libera la memoria occupata dal nome del file di output */
free(output_file);
}
}
else
{
/* azione: non e' possibile creare il nuovo file. */
/* stampo a video l' informazione ed esco dal programma */
printf("\nLa prego di controllare i permessi in scrittura della cartella\n");
printf("\nprima di riavviare questo programma, grazie .");
}
break;

default:
/* azione: stampa in output esempi di come utilizzare il programma */
printf("\nPer utilizzare questo programma");
printf("\ne' necessario specificare il nome del file.");
printf("\n\nEsempio:");
printf("\n\t exam nomefile.txt");
printf("\n\nE' possibile inoltre specificare il nome");
printf("\ndel file copia che il programma andra' a creare.");
printf("\n\nEsempio:");
printf("\n\t exam nomefile.txt nuovofile.txt");
printf("\n\nSe il nome del nuovo file non verra' specificato");
printf("\nquesto avra' lo stesso nome del file originale");
printf("\ncon l' aggiunta del suffisso \"%s\"", AUTO_SUFFIX);
break;
}

/* fine funzione main */
return (0);
}


/**********************************************/
/* definizione della funzione getFileOnExists */
/**********************************************/
FILE *getFileOnExists(
char *input_source_file /* input, file da leggere */
)
{

/* dichiarazione delle variabili locali alla funzione */
FILE *source_file; /* puntatore di tipo FILE che verra' restituito */

/* controllo: verifica che il file esista tentando di aprirlo in lettura */
if(!(source_file = fopen(input_source_file, "r")))
{
/* azione: manda in output un messaggio di errore file inesistente */
/* e richiede di scrivere nuovamente il file */
printf("\nImpossibile trovare il file\n\"%s\"", input_source_file);
printf("\nScriva il nome del file da copiare:\n");

/* azione: attende l' input dell' utente per assegnare il nomed del file */
scanf("%s", input_source_file);

/* azione: richiama se stessa sul puntatore da restituire ( ricorsiva ) */
source_file = getFileOnExists( input_source_file );
}

/* fine funzione getFileOnExists */
return source_file;
}




Makefile


exam : exam.o
gcc -ansi -Wall -O exam.o -o exam

exam.o : exam.c
gcc -ansi -Wall -O -c exam.c

pulisci:
rm -f exam.o

andr3a
16-03-2005, 17:49
RESOCONTO DEL PROFESSORE SUL PROGRAMMA


IMPLEMENTAZIONE DEL PROGRAMMA:
------------------------------


- COMPILABILE?
------------

No, riporta:
exam.c: In function `main':
exam.c:167: parse error before `char'
exam.c:173: `content' undeclared (first use in this function)
exam.c:173: (Each undeclared identifier is reported only once
exam.c:173: for each function it appears in.)
Il motivo e` che le variabili locali possono essere definite
solo all'inizio di un blocco racchiuso tra parentesi graffe.


- FUNZIONANTE?
------------

La variabile input_source_file dichiarata in getFileOnExists
viene assegnata mediante scanf senza che le sia preventivamente
stata allocata (tramite malloc) una quantita` di memoria sufficiente.
Cio` puo` causare errori a tempo d'esecuzione.


- STANDARD ANSI?
--------------

OK.


- STRUTTURATO?
------------

OK.


- ARTICOLATO?
-----------

OK.


- USO MEMORIA?
------------

OK.


- STILE DI PROGRAMMAZIONE?
------------------------

Misto di identificatori in italiano e inglese.
Misto di identificatori lunghi con uso di _ e di maiuscole.
Identificatore con parti in maiuscolo e in minuscolo.
Misto di codice in italiano e commenti in inglese.
I parametri argv e argc sono dichiarati coi tipi sbagliati.
L'identificatore a non e` evocativo di cio` che rappresenta.
Dopo parole chiave come if, while, for sarebbe meglio
lasciare uno spazio vuoto per maggiore leggibilita`.
Le convenzioni tipografiche standard stabiliscono ad esempio che:
"( usato qualora l'utente non indichi il nome del nuovo file )"
vada scritto cosi`:
"(usato qualora l'utente non indichi il nome del nuovo file)"
L'istruzione switch poteva essere resa con un piu` semplice if.
Per maggiore leggibilita`, conviene dichiarare tutte le variabili
locali all'inizio della funzione (mi riferisco p.e. a content).
Non ha molto senso definire la funzione getFileOnExists in modo
ricorsivo.


- MAKEFILE?
---------

Assente nella relazione.


TEST DEL PROGRAMMA:
-------------------

Assente.


NOTE:
-----

Sebbene non espressamente richiesto dalla specifica del problema,
sarebbe stato piu` opportuno dare al file di output un nome
uguale a quello che viene scritto nella sua prima linea tra asterischi.
Nel commento iniziale del programma, non e` vero che le linee
debbono essere ordinate in ordine crescente (frase peraltro oscura).
Quello che viene richiesto e` che le linee vengano numerate.

internet
16-03-2005, 19:09
Originariamente inviato da andr3a

$ gcc -ansi -Wall -O -c file.c

$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-slackware-linux/3.2.2/specs
Configured with: ../gcc-3.2.2/configure --prefix=/usr --enable-shared --enable-threads=posix --enabl
e-__cxa_atexit --disable-checking --with-gnu-ld --verbose --target=i386-slackware-linux --host=i386-
slackware-linux
Thread model: posix
gcc version 3.2.2


compila senza problemi, però...


Makefile


exam : exam.o
gcc -ansi -Wall -O exam.o -o exam

exam.o : exam.c
gcc -ansi -Wall -O -c exam.c

pulisci:
rm -f exam.o


Nel titolo riporti [ANSI C], di solito con questo termine si indica la versione ANSI C89 che non ti consente di dichiarare variabili ovunque. Cioè puoi solo dichiararle subito dopo l'inizio di un blocco.

ecco la grammatica


compound_statement
: '{' '}'
| '{' statement_list '}'
| '{' declaration_list '}'
| '{' declaration_list statement_list '}'
;


Ora il tuo prof. dice che non hai incluso un makefile e quindi presumo abbia dato lui i flag di verifica ANSI C89. Tra l'altro non ho capito che compilatore abbia usato, e con che flag.

Con gcc si fa così
To select this standard in GCC, use one of the options -ansi, -std=c89 or -std=iso9899:1990; to obtain all the diagnostics required by the standard, you should also specify -pedantic (or -pedantic-errors if you want them to be errors rather than warnings). See Options Controlling C Dialect.
http://gcc.gnu.org/onlinedocs/gcc-3.4.3/gcc/Standards.html#Standards

$ gcc -ansi -Wall -O -c file.c -pedantic
file.c: In function `main':
file.c:157: warning: ISO C89 forbids mixed declarations and code

cioè proprio il problema della dichiarazione della variabile content.

Il problema della variabile input_source_file invece c'è, e per risolverlo dovevi utilizzare un buffer di appoggio locale alla funzione, ora questo non basta a garantire l'assenza di errori in fase di run. Il fatto è che devi anche imporre un limite alla lunghezza della stringa letta da scanf. Se hai un buffer di 256 byte, scrivi scanf("%255s", stringa), 255 perchè ti serve un carattere finale per il NULL.
Se ti serve una stringa di lunghezza non predefinita, scanf non va più bene, devi crearti una funzione apposita basata su getchar(), malloc() e realloc().

andr3a
16-03-2005, 19:34
grazie mille per il report :)
pero' lui non ha mai detto che le locali andassero solo a inizio blocco :cry: .... comunque sia ...




Originariamente inviato da internet
Se ti serve una stringa di lunghezza non predefinita, scanf non va più bene, devi crearti una funzione apposita basata su getchar(), malloc() e realloc().
io avevo usato una stringa limitata da 256 caratteri, 255 piu' il finale ... e lui mi disse:

bocciato .... trallalla' trallalla' .... uso di arrays statici :dottò: :dottò: :dottò:


alche' non ho capito, visto che lui queste cose non le ha spiegate, se pretende tanto da me o se altri hanno fatto cose mai trattate durante il corso ... :dhò: :dhò:


boh :fagiano:

Loading