Oppure

Loading
03/04/10 15:49
gforce
Utilizzando getchar e putchar su una variabile di tipo char da me definita il valore di ritorno è sempre il primo carattere. Come faccio a gestire per esempio il 4^ carattere ? E come faccio a gestire tutta la parola ?

Inoltre ho scritto 2 frammenti di codici

#include <stdio.h>

int main()
{
	char ch;
	while (getchar() != '\n') {
		ch = getchar();
		putchar(ch);
	}
	return 0;
}
Con questo codice se io inserisco la parola ciao mi stampa io. Perchè non ciao ?

#include <stdio.h>

int main()
{
	char ch;
	while (1) {
		ch = getchar();
		putchar(ch);
	}
	return 0;
}
Con questo codice mi stampa tutta la parola.
Ultima modifica effettuata da gforce 03/04/10 16:08
aaa
03/04/10 16:39
Poggi Marco
Ho letto il tuo programma, e ho notato che usi getchar() come condizione del ciclo
while, di conseguenza, putchar() non stamperà tutte le lettere.
Ultima modifica effettuata da Poggi Marco 03/04/10 16:42
aaa
03/04/10 16:47
TheWorm
Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.
Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.

Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
	asm("movl , %eax");          // 4 = Scrivi
	asm("movl %esp, %ecx");      // %esp = Registro con l'input da scrivere
	asm("movl , %ebx");          // 1 = STDOUT (Terminal)
	asm("movl , %edx");          // 1 = Lunghezza output: 1 byte
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
//  asm("popa");                         // Reimposta i registri
	asm("call _start");                  // Chiama _start ye ricomincia il ciclo dall'inizio
}


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  {parsed_message}x80
movl , %eax
movl %esp, %ecx
movl , %ebx
movl , %edx
int  {parsed_message}x80
jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  {parsed_message}x80
movb , %al
movl %esp, %ecx
//movb , %bl
//movb , %dl
int  {parsed_message}x80
jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xDx80"); // Chiama il kernel, esegue il tutto asm("movl , %eax"); // 4 = Scrivi asm("movl %esp, %ecx"); // %esp = Registro con l'input da scrivere asm("movl , %ebx"); // 1 = STDOUT (Terminal) asm("movl , %edx"); // 1 = Lunghezza output: 1 byte asm("int Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.
Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
	asm("movl , %eax");          // 4 = Scrivi
	asm("movl %esp, %ecx");      // %esp = Registro con l'input da scrivere
	asm("movl , %ebx");          // 1 = STDOUT (Terminal)
	asm("movl , %edx");          // 1 = Lunghezza output: 1 byte
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
//  asm("popa");                         // Reimposta i registri
	asm("call _start");                  // Chiama _start ye ricomincia il ciclo dall'inizio
}


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  {parsed_message}x80
movl , %eax
movl %esp, %ecx
movl , %ebx
movl , %edx
int  {parsed_message}x80
jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  {parsed_message}x80
movb , %al
movl %esp, %ecx
//movb , %bl
//movb , %dl
int  {parsed_message}x80
jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xDx80"); // Chiama il kernel, esegue il tutto // asm("popa"); // Reimposta i registri asm("call _start"); // Chiama _start ye ricomincia il ciclo dall'inizio }


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.

Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
	asm("movl , %eax");          // 4 = Scrivi
	asm("movl %esp, %ecx");      // %esp = Registro con l'input da scrivere
	asm("movl , %ebx");          // 1 = STDOUT (Terminal)
	asm("movl , %edx");          // 1 = Lunghezza output: 1 byte
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
//  asm("popa");                         // Reimposta i registri
	asm("call _start");                  // Chiama _start ye ricomincia il ciclo dall'inizio
}


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  {parsed_message}x80
movl , %eax
movl %esp, %ecx
movl , %ebx
movl , %edx
int  {parsed_message}x80
jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  {parsed_message}x80
movb , %al
movl %esp, %ecx
//movb , %bl
//movb , %dl
int  {parsed_message}x80
jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xDx80 movl , %eax movl %esp, %ecx movl , %ebx movl , %edx int Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.
Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
	asm("movl , %eax");          // 4 = Scrivi
	asm("movl %esp, %ecx");      // %esp = Registro con l'input da scrivere
	asm("movl , %ebx");          // 1 = STDOUT (Terminal)
	asm("movl , %edx");          // 1 = Lunghezza output: 1 byte
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
//  asm("popa");                         // Reimposta i registri
	asm("call _start");                  // Chiama _start ye ricomincia il ciclo dall'inizio
}


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  {parsed_message}x80
movl , %eax
movl %esp, %ecx
movl , %ebx
movl , %edx
int  {parsed_message}x80
jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  {parsed_message}x80
movb , %al
movl %esp, %ecx
//movb , %bl
//movb , %dl
int  {parsed_message}x80
jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xDx80 jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.

Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
	asm("movl , %eax");          // 4 = Scrivi
	asm("movl %esp, %ecx");      // %esp = Registro con l'input da scrivere
	asm("movl , %ebx");          // 1 = STDOUT (Terminal)
	asm("movl , %edx");          // 1 = Lunghezza output: 1 byte
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
//  asm("popa");                         // Reimposta i registri
	asm("call _start");                  // Chiama _start ye ricomincia il ciclo dall'inizio
}


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  {parsed_message}x80
movl , %eax
movl %esp, %ecx
movl , %ebx
movl , %edx
int  {parsed_message}x80
jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  {parsed_message}x80
movb , %al
movl %esp, %ecx
//movb , %bl
//movb , %dl
int  {parsed_message}x80
jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xDx80 movb , %al movl %esp, %ecx //movb , %bl //movb , %dl int Non mi ricordo molto del C, ma nel primo codice usi due volte getchar, uno nella condizione e uno nelle istruzioni! Quindi il primo getchar nelle condizioni prende il primo carattere, ma poi nelle istruzioni prendi il secondo e stampi quello. Poi rifai da capo e prendi il terzo, poi il quarto e stampi il quarto.
Quindi potresti togliere il getchar nelle istruzioni e lasciare quello nelle condizioni così:

while ( (ch = getchar()) != '\n') {


E invece di usare un MALEFICO while(1), il tutto diventa:

#include <stdio.h>

int main()
{
    char ch;
    while( (ch = getchar()) != '\n' ) {
        putchar( ch );
    }
    putchar( ch );
    return 0;
} 


Se ti serve leggere e stampare stringhe inserite in input al programma continuamente evitando che si chiuda tutto, cioè non una volta sola (tipo col comando "cat";), puoi fare così:

#include <stdio.h>

int main()
{
	char ch;
	for( ;; ) {
		while( (ch = getchar()) != '\n' ) {
			putchar( ch );
		}
		putchar( ch );
	}
	return 0;
}


Anche se ti conviene così:

#include <stdio.h>

int main()
{
        char ch;
        for( ;; ) {
                ch = getchar();
                putchar( ch );
        }
        return 0;
}


Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:

main(){for(;;)putchar(getchar());}


oppure

main(){putchar(getchar());main();}


Inutile far notare la bruttura delle ultime due...

Sicuramente non sono stato chiaro, ma il codice parla da solo, quasi sempre. Cosa buona e giusta potrebbe anche essere un libro/manuale sul C: non mangiano mica! Al massimo ti mangia il portafoglio se il manuale è buono.

Poi se vuoi fare qualcosa di leggero e veloce, puoi semplificare tutto in assembly (32 bit). Questo funziona per me:

void _start()
{
//  asm("pusha");                      // Salva i valori dei registri
	asm("movl , %eax");          // 3 = Leggi
	asm("movl , %edx");          // 1 = Lunghezza input: 1 byte
	asm("movl %esp, %ecx");      // %esp = Registro dove salvare momentaneamente l'input
	asm("movl , %ebx");          // 1 = STDIN
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
	asm("movl , %eax");          // 4 = Scrivi
	asm("movl %esp, %ecx");      // %esp = Registro con l'input da scrivere
	asm("movl , %ebx");          // 1 = STDOUT (Terminal)
	asm("movl , %edx");          // 1 = Lunghezza output: 1 byte
	asm("int  {parsed_message}x80");                 // Chiama il kernel, esegue il tutto
//  asm("popa");                         // Reimposta i registri
	asm("call _start");                  // Chiama _start ye ricomincia il ciclo dall'inizio
}


E lo compili senza includere headers o librerie standard: senza "#include <stdio.h>" e con l'opzione -nostdlib per il compilatore (io uso gcc). La differenza si vede: da 4649 bytes a 1037 bytes... un po' meglio eh?

...Oppuuuure, lo scrivi direttamente in asm visto che ci sei. In my_cat.S:

.global _start

_start:
movl , %eax
movl , %edx
movl %esp, %ecx
movl , %ebx
int  {parsed_message}x80
movl , %eax
movl %esp, %ecx
movl , %ebx
movl , %edx
int  {parsed_message}x80
jmp _start


E poi: as -o my_cat.o my_cat.S && ld -o my_cat my_cat.o && rm my_cat.o
L'eseguibile adesso mi si è ridotto a 708 bytes!
Se poi hai tempo da perdere, puoi accorciarlo ancora un pochino, ottenendo 692 bytes (sulla mia macchina):

.global _start

_start:
xorl %eax, %eax
xorl %ebx, %ebx
xorl %edx, %edx
movb , %al
inc  %edx
movl %esp, %ecx
inc  %ebx
int  {parsed_message}x80
movb , %al
movl %esp, %ecx
//movb , %bl
//movb , %dl
int  {parsed_message}x80
jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xDx80 jmp _start


Probabilmente potresti renderlo ancora più corto, non sono un guru. Per esempio "jmp _start" viene tradotto "e9 e7 ff ff ff" mentre credo si possa accorciare a "eb f9". Ah comunque il codice non è perfetto, potrebbe non funzionare in alcuni casi perchè ho badato solo alla lunghezza, non alla correttezza... in pratica funziona.

Morale della favola: Ridurre un programma al 15%, sicuramente è *cool* e ne aumenta la velocità di esecuzione.
PS: Si, ok, ovviamente non ce ne frega un cazzo se scriviamo due righe di codice (tipo queste) e se abbiamo un 8 core sotto il culo xD
Ultima modifica effettuata da TheWorm 22/04/10 17:33
aaa