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.
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ì:
E invece di usare un MALEFICO while(1), il tutto diventa:
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ì:
Anche se ti conviene così:
Se ti serve qualcosa di ancora più corto, ecco un'altra (pessima) alternativa:
oppure
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:
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:
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):
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
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