Newsgroup: it.comp.os.linux.development
Titolo: perche' questo in DOS va e in Linux no ?

Salve a tutti,
 come da subject, il seguente codice in Dos va benone ma in Linux no:
--------------------- cut here ------------------------------- 
#include "stdio.h"
#include "string.h"
char *Espandi(char *testo2)
{
 char testo1[255]="abcdefghil";
 char *ret;
 ret=strcat(testo1,testo2);
 return ret;
}
int main()
{
 printf("\n\r Testo = %s \n\r",Espandi("mnopqrstuvz"));
 return 0; 
}
-------------------------------------------------------------
in particolare sotto DOS mi ritorna esattamente la stringa:
"abcdefghilmnopqrstuvz"
mentre sotto Linux si incasina tutto.
Pero' ho notato che, se nel main inserisco come prima istruzione
la seguente:
printf("");
allora tutto va bene.
Che succede ?
E' printf che fa qualche casino ?
Grazie.
-- 
  ________
 |\      /|
 | \____/ |  Sender:
 |        |  
mimmo....@libero.it
 
 |________|

 }
Ahi. C'è un errore piuttosto grave qui. Sebbene la cosa sfugga
inevitabilmente al compilatore (che in situazioni simili ti avverte con un
warning), la funzione di fatto restituisce l'indirizzo di una variabile
locale. Consulta strcat(3).
Hai tre opzioni:
 1. rendere testo1 static
 2. allocare dinamicamente il buffer
 3. passare l'indirizzo di un buffer come argomento della funzione
Ognuna ha i suoi vantaggi e svantaggi.
Max

allora tutto va bene.
E` un caso, esattamente come e` un caso che il programma funzioni con un
compilatore DOS.
-- 
ciao, | [Per rispondere togli "toglimi" dal mio indirizzo.]
Marco | * The Internet is full. Go away.  -- Joel Furr *
      | (Ri)scoprire fidonet: 
http://bbs.mi.linux.it

  char testo1[255]="abcdefghil";
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Il problema sta qui: uscendo dalla funzione "Espandi" il puntatore a
testo1 non è più valido, in quanto testo1 è una variabile temporanea,
allocata sullo stack. La soluzione sta o nell'usare un buffer globale, o
nell'allocare dinamicamente la memoria.
Saluti,
Fabio Alemagna

 Un programma deve essere terminato con exit, non return.
Ma quando mai? exit() serve solo quando devi uscire dal programma in un
qualsiasi momento, se sei arrrivato semplicemente alla fine del main
devi usare return.
Ciao,
Fabio Alemagna

 del main devi usare return.
Tanto per esporre una terza corrente di pensiero, da quanto ne
sapevo usare exit() o return alla fine del main e` esattamente
uguale.
-- 
Ditemi perche`... se la mucca fa muuu il merlo non fa meee?   _/Davide\_
   -- Elio                                                    \Alberani/

 uguale.
Infatti, e proprio per questo non ha senso usare exit(). 
E' una questione di stile :)
Saluti,
Fabio Alemagna

]

 come da subject, il seguente codice in Dos va benone ma in Linux no:
Non e' che in DOS va benone. In DOS non ti accorgi della cosa orribile
che e' successa, cioe' che la printf() va a puntare ad una zona di RAM
che apparteneva alla funzione Espandi(), ma, poiche' Espandi(), quando
arrivi alla printf(), e' terminata, APPARTIENE A QUALCUN ALTRO.
In DOS, *per puro caso*, dentro ci sono ancora i dati che Espandi() ci
ha messo dentro, e ti SEMBRA che funzioni tutto.
Un po' come uno che ha venduto casa, ma siccome la serratura "PER ORA"
non e' stata cambiata, crede di poterci ancora entrare e abitare.
Se ti serve che il buffer sopravviva, dichiaralo static.
+++
Sarebbe meglio, fra le altre cose, scrivere:
char *Espandi(const char *testo2)
{
	const char *prefix = "abcdefghil";
	size_t length;
#ifdef USE_DYNAMIC
	static char *buffer = NULL;
	if (buffer)
	{
		free(buffer);
		buffer = NULL;
	}
#else
	// ATTENZIONE allo "static"!
	static char buffer[255];
#endif
	length = strlen(testo2) + strlen(prefix) +1;
#ifdef USE_DYNAMIC
	if ((buffer = (char *) malloc(length))==NULL)
		return "*OUT OF MEMORY*";
	snprintf(buffer, length, "%s%s", prefix, testo2);
#else
	snprintf(buffer, sizeof(buffer), "%s%s", prefix, testo2);
#endif
	return buffer;
}
Leonardo
".signature": bad command or file name

exit(val)
Quasi. I risultati sono gli stessi, ma serve qualche istruzione in piu`
(verificato con disassemblato del programma e della libc alla mano).
Inoltre, suggerisco la lettura delle FAQ sul C, domanda 11.16.
(
http://lysator.liu.se/C/
)


(
http://lysator.liu.se/C/
)
Visto, i problemi in genere sorgono in situazioni non pulitissime, che
sarebbe meglio evitare (tra l'altro in C++ una exit() potrebbe essere
alquanto deleteria per gli oggetti locali in main...)


 Un programma deve essere terminato con exit, non return.
Dove lo hai letto, su Topolino?!?! Scherzi a parte, alla fine del main
return o exit() sono equivalenti.
--
 Ciao, Luca.
 Reply to 
luca....@tiscalinet.it

alquanto deleteria per gli oggetti locali in main...)
No di certo, disassembla exit(3) se non ti fidi.


No di certo, disassembla exit(3) se non ti fidi.
Ne invoca il distruttore?


Un programma deve essere terminato con exit, non return.
Questa non la sapevo. Quello che mi lascia perplesso pero' e' che ho visto
decine e decine di programmi in cui il main si chiude con un return
piuttosto che con exit.
Pensavo che exit forzasse la chiusura del programma (ad esempio lo uso
quando fopen mi ritorna un errore nell'apertura di un file fondamentale per
il proseguio del programma) e dunque metterlo come istruzione di chiusura
normale credevo fosse "formalmente" sbagliato.
Grazie (a te e a tutti gli altri che mi stanno rspondendo).


}
M$DOG si che č un SO con le palle, quando fai un errore del genere
lui se ne accorge e ti corregge al volo il programma,
e anche se hai un puntatore a memoria deallocata
lui la rialloca e tutto funziona!!!
non ne posso piů di linux e i suoi buffer overflow.
o chiuso con sto' schifo di linux, io ritorno al DOS:-)
grazie bill senza di te cosa faremmo;-)

 Ne invoca il distruttore?
Mi rispondo io: no
Prova a compilare questo e vedi che il distruttore di C non viene
invocato, mentre lo e' con return (se il distruttore di C dovesse fare
qualcosa di importante all'uscita saresti fregato)
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class C
{
  string s;
public:
  C(const string &_s):
    s(_s){};
  ~C()
  {
    cout<<"Destructing "<<s<<"\n";
  }
};
main()
{
  C c("prova");
  exit(0);
}

Ne invoca il distruttore?
Certo.
exit(3) != _exit(2)


 
Vedi altro esempio
Dal manuale:
EXIT(3)             Linux Programmer's Manual             EXIT(3)
DESCRIPTION
       The  exit()  function  causes  normal program termination and the
       value of status is returned to the parent.  All functions  regis­
       tered with atexit() and on_exit() are called in the reverse order
       of their registration, and  all  open  streams  are  flushed  and
       closed.
 
L'unica cosa che garantisce e' la chiusura corretta dei flussi, per fare
altro devi usare atexit() e onexit()
ByE,
FF


ICQ: <38811133>

compilatore DOS.
Daccordo anche qua.


avrei dovuto dichiarare static ret e non testo1, vero ?
Si, pero dovevi comunque dichiarare ret non come puntatore a char ma
come vettore di caratteri (stessa cosa, ma con char ret[256] ti creavi
lo spazio fisico dove concatenare testo1 e testo2).


trattera' in modo opportuno.
Ricordo che in dos alcune funzioni dalla libreria conio.h (Turbo C++ 3.0)
avevano bisono del '\r' per tornare a inizio riga (non propriamente ANSI
C): si verificava senno` l'effetto scalettatura tipico di alcune
stampanti DOS (CR + LF invece di LF e basta).


 stampanti DOS (CR + LF invece di LF e basta).
Questo lo ignoro, io mi riferivo allo standard.
