Két yes implementáció

 ( hrgy84 | 2010. március 23., kedd - 1:03 )

Döbbenten vettem észre, hogy a MinGW/MSYS rendszer nem tartalmazza a yes nevű binárist. Gyorsan gyártottam kettőt is.

#include <stdio.h>
#include <malloc.h>
#include <string.h>

int main(int argc, char **argv) {
        char *msg = _alloca(256); // malloc(256);
        char *p;
        int i, l = 0;

        memset(msg, 0, 256);
        
        if(argc == 1) {
                strncat(msg, "y", 1);
        } else {
                for(i = 1; i < argc; i++) {
                        l += strlen(argv[i]) + 1;
                        if(l >= 256) {
                                break;
                        }
                        strncat(msg, argv[i], strlen(argv[i]));
                        strncat(msg, " ", 1);
                }
                l = strlen(msg) -1;
                p = msg + l;
                if(*p == ' ') {
                        *p = '\0';
                }
        }

        while(1) {
                printf("%s\n", msg);
        }
}

Ez volt az első implementáció. Hátránya, hogy korlátos, nem tud 256 byte-nál nagyobb sztringet kezelni.
Azután gondolkodtam, és megszületett a yes2:

#include <stdio.h>

int main(int argc, char **argv) {
        int i;
        if(argc == 1) {
                while(1) {
                        printf("y\n");
                }
        } else {
                while(1) {
                        for(i = 1; i < argc; i++) {
                                if(i > 1) {
                                        printf(" ");
                                }
                                printf("%s", argv[i]);
                        }
                        printf("\n");
                }
        }
}

Kicsi (majdnem negyede az első verziónak a lefordított bináris), gyors. Ha még gyorsabbá akarnám tenni, akkor be lehetne tenni egy else ágat az argc == 2 esetre (ekkor ugyanis csak egy paramétert kell végtelen ciklusba kiíratni, kiesne a for ciklus).

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

a malloc/_alloca + memset parost miert nem calloc helyettesiti? Gyorsabb igy?

Az _alloca azert lett, mert a yes by definition csak ctrl+c -re all le. Viszont, mivel igy eselyem sincs a free() hivasara, muszaj explicite a stacken helyet foglalni. A calloc ugy tudom, nem a stacken foglal memoriat. A memset-et meg mar megszoktam masutt.

Ja, es ugye linuxon nem _alloca hanem alloca, csak mar a #ifdef/#define parossal hajnal egykor nem volt kedvem szorakozni.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

"csak ctrl+c -re all le. Viszont, mivel igy eselyem sincs a free() hivasara"

jujj, most ugy teszek, mintha ezt nem olvastam volna ;)

--
NetBSD - Simplicity is prerequisite for reliability

Persze, lehet atexittel, meg signal handlerekkel szorakozni, de most komolyan: egy ekkora programnal megeri?
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Most megnéztem Macen a BSD félét, az a tiéddel ellentétben csak az első argumentumot írja ki, amennyiben egynél több is van. Érdekes, eszerint a for ciklussal ott nem bajlódtak.

Igen, vegulis ez az, ami megkulonbozteti a ket implementaciot egymastol. A for ciklustol ugyanis a masodik lassabb lesz, hiszen mindig be kell jarnia az argv tombot, az elso viszont memoriat igenyel a stacken - ami valtozo, hogy mennyi van.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

http://nxr.netbsd.org/xref/src/usr.bin/yes/yes.c

ez miert nem jo?

--
NetBSD - Simplicity is prerequisite for reliability

1) nem neztem a NetBSD-set, mert tobbszor szaladtam mar ra, hogy nem lehetett 1:1 hasznalni az ottani forrasokat, annyira meg nem ismerem a NetBSD forrasfat, hogy meg mertem volna lepni a portolast.
2) ld. fentebb. Ez foleg akkor erdekes, ha folyamatosan olyanokat kell valaszoljon, hogy "Igen, tudom mit csinalok". Ezt a ti verziotok csak idezojelekkel tudja, az en masodik verziom viszont folyamatosan az argv tombot cseszteti. Persze, cserebe a ciklus overheadjevel lassabb a kiiras.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

meg a sok strlen() hivas is lassít.
A ternaris operatorral meg lehetne egyszerusiteni a masodik kododat is.
elso eseteben nem ertem az alloca hasznalatat. minek?
es nem vizsgalod a visszateresi erteket sem.

Van egy kis kulonbseg. Az elso esetben csak az inicializalas lassu, maga a kiiras mar a printf konstans idejevel megy. A masodik esetben azonban a tombbejaro for ciklus minden kulso ciklus eseteben terhel.

Az alloca-t azert hasznaltam, mert ez volt a legegyszerubb modja annak, hogy ne kelljen belemerulnom abba, hogy Windows alatt a Ctrl+C hogyan allitja le valojaban a programokat (ejjel egykor nem volt kedvem pocsolni vele), igy a stacken foglalok helyet, aminel kevesbe erdekes, ha nem szabaditom fel (mert ugye a megszakitas kezelesenek ignoralasaval ez tortenik).

A visszateresi erteket ket okbol nem vizsgalom
- Ha nincs 256 byte a stacken, akkor valami baromi nagy gaz lehet a rendszerben, a legkissebb dolog egy null-ponter dereference
- Nem bolondbiztos programot akartam irni, hanem elso korben egy mukodot. Ha eljutunk eddig, utana mar lehet finomkodni vele, nekem akkor ott volt szuksegem egy yes-re.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Tudom, ez rossz megközelítés, de az miért baj, ha a heap-en foglalsz memóriát? A gyakorlatban az operációs rendszer úgyis felszabadítja, amikor megszakad a program futása, nem?

Ha nem, akkor meg szar van, 256 byte memoria oda.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

És mikor nem?

Mit tudom en, nekem eleg a lehetoseg is, hogy aggodjak.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

:) A for (;;) rém elegáns a while(1) -el szemben.
Amúgy érdekes összevetni az implementációkat, mert ez egy olyan kis program, ami első nekifutásra belátható összetettségű, és mégis többféle az a bizonyos nekifutás...

Én a

#define ever ;;

for(ever){

}

verziót szeretem...

--
Soli Deo Gloria

Az fputs tenyleg jo otlet, erre igy nem is gondoltam. A putchar-t viszont valahogy nem szeretem... Ez ilyen megmagyarazhatatlan ellenszenv, nincs konkret oka.

Megnezegettem. Erdekes a true es a false implementacioja. Szerintem a return gyorsabb mint az exit() es kisebb kodot ad.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Az argc mikor lesz kisebb, mint 1? :D