Forum Doku Wiki Blog

Forumsarchiv 2009, Juni
C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

archivierte Beiträge lesen

  1. (SONSTIGES) C: Verlinken statischer Bibliothek führt zu falschem Ergebnis von *Markus, 11. 06. 2009, 21:47

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 11. 06. 2009, 21:47 Uhr von *Markus veröffentlicht.

Hallo,

ich wollte testen, wie ich statische Bibliotheken verwenden kann. Dazu habe ich mir ein kleines Testprogramm geschrieben, das den Durchschnitt errechnet, wobei die Berechnung in der statischen Bibliothek vonstatten geht:

durchschnitt.h
---------------------------


#define MAX 30
#include <stdio.h>
#include <stdlib.h>

double durchschnitt(double arr[], int arrused);


durchschnitt.c
--------------------------


double durchschnitt(double arr[], int arrused)   {
        
        double wert = 0.0;
        
        for (int i = 0; i < arrused; i++)  {
                 wert += arr[i];
        }
        
        if (arrused != 0)
                return wert /= arrused;
        
        return wert;        
}


Main.c
-----------------------------


#include "durchschnitt.h"

int main(void)   {

        int c;
        int j;
        int arrayused;
        double array[MAX];
        char hilfsarray[10];
        j = arrayused = 0;
        
        while (arrayused < MAX && ((c = getchar()) != EOF))   {
                 if ( (c >= '0' && c <= '9') || c == '.')  {
                           hilfsarray[j++] = c;
                 }
                 else  {
                           hilfsarray[j] = '\0';
                           array[arrayused++] = atof(hilfsarray);
                           j = 0;
                 }
                                 
        }

        for (int i = 0; i < arrayused; i++)  {
                printf("Zahl %d: %f\n", i+1, array[i]);
        }
        
        printf("Durchschnitt: %f\n", durchschnitt(array, arrayused));

return 0;
}




Wäre dieser Code in einer einzigen Datei stehen, würde der Durchschnitte richtig berechnet werden. Ironischerweise funktionier es aber nicht, wenn ich dies als Bibliothek auslagere. Im Ergebnis werden nämlich Hausnummern angezeigt. Gebe ich zB nur eine Zahl ein, zB 5, bekomme ich als Ergebnis:
5
Zahl 1: 5.000000
Durchschnitt: 0.057253

Gebe ich 3 ein, bekomme ich folgendes:
3
Zahl 1: 3.000000
Durchschnitt: 0.073297

Der Code ist richtig. Ich habe alle per Copy&Paste aus der Gesamtdatei übernommen. Es muss also irgend etwas beim Zerteilen in Einzeldateien oder beim Kompilieren schief laufen, aber was? Ich ging dabei so vor:

$ gcc -c durchschnitt.c -o durchschnitt.o -std=c99
$ ar rcs libdurchschnitt.a durchschnitt.o
$ gcc -static durchschnitt.h Main.c -L. -ldurchschnitt -o Main_statisch -std=c99


Aufruf durch ./Main_statisch

Kann sich jemand dieses Phänomen erklären?

Danke,
Markus

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 11. 06. 2009, 22:20 Uhr von Encoder veröffentlicht.

Ohne den Code gelesen zu haben, aber da gibts verschiedene Aufrufkonventionen. cdecl und so weiter, vielleicht liegts dran dass du die Funktion falsch aufrufst?

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 11. 06. 2009, 23:46 Uhr von *Markus veröffentlicht.

Hallo,

> Ohne den Code gelesen zu haben, aber da gibts verschiedene Aufrufkonventionen. cdecl und so weiter, vielleicht liegts dran dass du die Funktion falsch aufrufst?

ich wusste gar nicht, dass man sich darum kümmern muss, da dies ja der C-Compiler (gcc) für einen erledigt. Gibt es da irgend etwas, das ich wissen sollte?

Markus

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 01:25 Uhr von Encoder veröffentlicht.

> ich wusste gar nicht, dass man sich darum kümmern muss, da dies ja der C-Compiler (gcc) für einen erledigt.
Der erledigt es so wie man es ihm sagt, oder wie er es annimmt wenn man ihm nichts sagt. Aber ich hab echt keine wirkliche Ahnung davon, das ist schon ne Weile her.
Was mich eh wundert, du sagst statische Bibliothek. Ist das nur eine separate Quellcodedatei oder was meinst du damit?
Ne dll wär ja dynamisch, da zieht das mit den Konventionen.

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 11. 06. 2009, 22:44 Uhr von Alexander (HH) veröffentlicht.

Moin Moin!

Ich bin bei C etwas eingerostet, aber ...

> double wert = 0.0;

0.0 ist ein single, kein double.

>
> for (int i = 0; i < arrused; i++)  {
> wert += arr[i];
> }
>
> if (arrused != 0)

Auch wenn arrused<0? Nicht gut.

> return wert /= arrused;
>
> return wert;

x/0=0? Mein Mathelehrer rotiert im Grabe!

> }
> [/code]
>
> Main.c
> -----------------------------
>
> [code lang=c]
> #include "durchschnitt.h"
>
> int main(void)   {
>
> int c;
> int j;
> int arrayused;
> double array[MAX];
> char hilfsarray[10];
> j = arrayused = 0;
>
> while (arrayused < MAX && ((c = getchar()) != EOF))   {
> if ( (c >= '0' && c <= '9') || c == '.')  {
>   hilfsarray[j++] = c;
> }
> else  {
>   hilfsarray[j] = '\0';
>   array[arrayused++] = atof(hilfsarray);

atof liefert keine Fehlermeldungen, nutze strtod.

>   j = 0;
> }

Und was passiert, wenn c weder NUL noch Ziffer noch Punkt ist?
>
> $ gcc -c durchschnitt.c -o durchschnitt.o -std=c99
> $ ar rcs libdurchschnitt.a durchschnitt.o
> $ gcc -static durchschnitt.h Main.c -L. -ldurchschnitt -o Main_statisch -std=c99

Laß gcc mal mit -Wall -pedantic laufen und beseitige alle Warnungen.

Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 11. 06. 2009, 22:56 Uhr von Christian Seiler veröffentlicht.

Hallo Alexander,

> 0.0 ist ein single, kein double.

Nein, das ist falsch. 0.0 ist vom Typ double, 0.0f ist vom Typ float und 0.0L ist vom Typ long double.

Viele Grüße,
Christian

--
Mein "Weblog" [RSS]
Using XSLT to create JSON output (Saxon-B 9.0 for Java)

»I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
            -- Kommentar bei TDWTF

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 11. 06. 2009, 23:44 Uhr von *Markus veröffentlicht.

Hallo,

> »» if (arrused != 0)
>
> Auch wenn arrused<0? Nicht gut.

Kommt nicht vor, da man ja bei 0 anfängt zu zählen und nicht bei Minuszahlen.

> »» return wert /= arrused;
> »»
> »» return wert;
>
> x/0=0? Mein Mathelehrer rotiert im Grabe!

Wie kommst du auf x/0? Was ist der Durschnitt einer einzelnen Zahl?

> »» }
> »» [/code]
> »»
> »» Main.c
> »» -----------------------------
> »»
> »» [code lang=c]
> »» #include "durchschnitt.h"
> »»
> »» int main(void)   {
> »»
> »» int c;
> »» int j;
> »» int arrayused;
> »» double array[MAX];
> »» char hilfsarray[10];
> »» j = arrayused = 0;
> »»
> »» while (arrayused < MAX && ((c = getchar()) != EOF))   {
> »» if ( (c >= '0' && c <= '9') || c == '.')  {
> »»   hilfsarray[j++] = c;
> »» }
> »» else  {
> »»   hilfsarray[j] = '\0';
> »»   array[arrayused++] = atof(hilfsarray);
>
> atof liefert keine Fehlermeldungen, nutze strtod.
>
> »»   j = 0;
> »» }
>
> Und was passiert, wenn c weder NUL noch Ziffer noch Punkt ist?

Darum kümmert sich glücklicherweise atof.


Markus

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 00:29 Uhr von Alexander (HH) veröffentlicht.

Moin Moin!

> Hallo,
>
> »» »» if (arrused != 0)
> »»
> »» Auch wenn arrused<0? Nicht gut.
>
> Kommt nicht vor, da man ja bei 0 anfängt zu zählen und nicht bei Minuszahlen.

Deine Funktion definiert arrused als signed int, und der kann negativ werden - auch gelegentlich mal durch ein ++.

Wenn Du garantiert nur zählst, nimm keine signed ints, sondern ein unsigned int, unsigned long, oder unsigned long long.

>
> »» »» return wert /= arrused;
> »» »»
> »» »» return wert;
> »»
> »» x/0=0? Mein Mathelehrer rotiert im Grabe!
>
> Wie kommst du auf x/0?

Definition des Durchschnitts: Summe aller Einzelelemente geteilt durch die Anzahl der Elemente.

Wenn arrused ungleich 0 ist, berechnest Du wert/arrused und gibst das zurück. (Die Zuweisung an wert halte ich da übrigens für unnötig.) Ansonsten ist wert=0.0 und arrused=0.

Du lieferst für das Ergebnis einer Division durch 0 schlicht 0 zurück, und das ist falsch.

> Was ist der Durschnitt einer einzelnen Zahl?

Falsche Frage.

Trotzdem erstmal die Antwort: Die Zahl selbst. Das wird durch if (arrused != 0) return wert /= arrused; korrekt abgedeckt.

Was ist der Durchschnitt einer leeren Liste, wenn arrused==0?

Er ist nicht definiert, Du gibst aber 0.0 zurück.

> »» Und was passiert, wenn c weder NUL noch Ziffer noch Punkt ist?
>
> Darum kümmert sich glücklicherweise atof.

"Rhababerquark" hältst Du also für eine gültige Eingabe, wenn nach einer Gleitkommazahl gefragt ist?

strtod gibt Dir hier eine klare Aussage, dass Müll eingegeben wurde, atof verschweigt Dir das und liefert stattdessen eine willkürlich ausgesuchte Zahl.

Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 08:28 Uhr von *Markus veröffentlicht.

Hallo,

> Trotzdem erstmal die Antwort: Die Zahl selbst. Das wird durch if (arrused != 0) return wert /= arrused; korrekt abgedeckt.
>
> Was ist der Durchschnitt einer leeren Liste, wenn arrused==0?
>
> Er ist nicht definiert, Du gibst aber 0.0 zurück.

Ok, da hast du zwar recht. Das Programm war aber sowieso zum testen für mich selbst bestimmt, also habe ich auch gar nicht alle Sicherheitsvorkehrungen bezügl. der Eingabe berücksichtigt.

Mit geht es aber eigentlich darum, warum das Einbinden der statischen Bibliothek zu falschen Ergebnissen führt?

Markus.

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 09:27 Uhr von Alexander (HH) veröffentlicht.

Moin Moin!

> Mit geht es aber eigentlich darum, warum das Einbinden der statischen Bibliothek zu falschen Ergebnissen führt?

Kann ich nicht nachvollziehen:

Makefile:

CFLAGS += -std=c99

default: clean test

clean:
        rm -f *.o *.a allinone static

all: allinone static

allinone: allinone.o

allinone.o: allinone.c

allinone.c: durchschnitt.h durchschnitt.c Main.c
        cat $^ > $@

static: Main.c libdurchschnitt.a
        gcc -static durchschnitt.h Main.c -L. -ldurchschnitt -o static -std=c99

libdurchschnitt.a: durchschnitt.o
        ar rcs libdurchschnitt.a durchschnitt.o

durchschnitt.o: durchschnitt.c

test: allinone static
        for t in 3 5 "1 2 3" quark ""; do for f in $^ ; do echo "$$t | $$f" ; echo $$t | $$f ; done ; done


make:

rm -f *.o *.a allinone static
cc -std=c99   -c -o allinone.o allinone.c
cc   allinone.o   -o allinone
cc -std=c99   -c -o durchschnitt.o durchschnitt.c
ar rcs libdurchschnitt.a durchschnitt.o
gcc -static durchschnitt.h Main.c -L. -ldurchschnitt -o static -std=c99
for t in 3 5 "1 2 3" quark ""; do for f in allinone static ; do echo "$t | $f" ; echo $t | $f ; done ; done
3 | allinone
Zahl 1: 3.000000
Durchschnitt: 3.000000
3 | static
Zahl 1: 3.000000
Durchschnitt: 3.000000
5 | allinone
Zahl 1: 5.000000
Durchschnitt: 5.000000
5 | static
Zahl 1: 5.000000
Durchschnitt: 5.000000
1 2 3 | allinone
Zahl 1: 1.000000
Zahl 2: 2.000000
Zahl 3: 3.000000
Durchschnitt: 2.000000
1 2 3 | static
Zahl 1: 1.000000
Zahl 2: 2.000000
Zahl 3: 3.000000
Durchschnitt: 2.000000
quark | allinone
Zahl 1: 0.000000
Zahl 2: 0.000000
Zahl 3: 0.000000
Zahl 4: 0.000000
Zahl 5: 0.000000
Zahl 6: 0.000000
Durchschnitt: 0.000000
quark | static
Zahl 1: 0.000000
Zahl 2: 0.000000
Zahl 3: 0.000000
Zahl 4: 0.000000
Zahl 5: 0.000000
Zahl 6: 0.000000
Durchschnitt: 0.000000
 | allinone
Zahl 1: 0.000000
Durchschnitt: 0.000000
 | static
Zahl 1: 0.000000
Durchschnitt: 0.000000


gcc --version:

gcc (GCC) 4.2.3
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.



Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 09:32 Uhr von Alexander (HH) veröffentlicht.

Moin Moin!

Kleiner Denkanstoß:

echo 5 | static ; echo "5a" | static ; echo "5ab" | static ; echo "5 garbage in garbage out" | static
Zahl 1: 5.000000
Durchschnitt: 5.000000
Zahl 1: 5.000000
Zahl 2: 0.000000
Durchschnitt: 2.500000
Zahl 1: 5.000000
Zahl 2: 0.000000
Zahl 3: 0.000000
Durchschnitt: 1.666667
Zahl 1: 5.000000
Zahl 2: 0.000000
Zahl 3: 0.000000
Zahl 4: 0.000000
Zahl 5: 0.000000
Zahl 6: 0.000000
Zahl 7: 0.000000
Zahl 8: 0.000000
Zahl 9: 0.000000
Zahl 10: 0.000000
Zahl 11: 0.000000
Zahl 12: 0.000000
Zahl 13: 0.000000
Zahl 14: 0.000000
Zahl 15: 0.000000
Zahl 16: 0.000000
Zahl 17: 0.000000
Zahl 18: 0.000000
Zahl 19: 0.000000
Zahl 20: 0.000000
Zahl 21: 0.000000
Zahl 22: 0.000000
Zahl 23: 0.000000
Zahl 24: 0.000000
Durchschnitt: 0.208333

Möchtest Du etwas über nicht abgefangene Fehler, insbesondere rund um atof, anmerken?

Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 09:37 Uhr von *Markus veröffentlicht.

Hallo,

> Möchtest Du etwas über nicht abgefangene Fehler, insbesondere rund um atof, anmerken?

wie ich schon erwähnte, habe ich falsche Eingaben kaum berücksichtigt, da das Programm nur für mich selbst zum Testen vorgesehen ist. Und ich weiß ja schließlich, was ich eingaben muss. :)

Markus

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 09:35 Uhr von *Markus veröffentlicht.

Hallo,

danke für die Hilfe. Ich werde das heute Abend, wenn ich zu Hause bin, gleich nochmals testen. Auf den ersten Blick kann ich aber gar keine Unterschiede beim Kompilieren erkennen...

Markus

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 09:45 Uhr von Andreas Pflug veröffentlicht.

Hallo,

> $ gcc -c durchschnitt.c -o durchschnitt.o -std=c99
> $ ar rcs libdurchschnitt.a durchschnitt.o
> $ gcc -static durchschnitt.h Main.c -L. -ldurchschnitt -o Main_statisch -std=c99

ich habe das hier mit gcc Version 4.3.2 und ar aus
den binutils 2.1.18.20080103 mal genauso probiert und kann
kein auffälliges Verhalten finden, d. h. der Durchschnitt
wird - auch mit Verwendung der Library - korrekt ausgegeben.

Ein paar Anmerkungen seien mir noch erlaubt:

- durchschnitt.h:
Die Zeilen


#define MAX 30
#include <stdio.h>
#include <stdlib.h>


werden allesamt nur in main.c benötigt. Aus Code-Design-Aspekten
würde ich diese Zeilen daher auch in main.c schreiben, zumal es
ja auch sein kann, dass durchschnitt.h von anderen Codes
eingebunden sind, die evtl. <stdio.h> etc. schon anderweitig
inkludieren oder die andere Vorstellungen von MAX haben.

- durchschnitt.c:
Einleuchtender ist es i.d.R., fehlerhafte Parameter gleich
ganz am Anfang einer Funktion abzufangen. Ich hätte daher
am Anfang der Funktion eine Zeile wie folgt erwartet:

if (arrused<=0) return 0.0;

Die Rückgabe return wert /= arrused;
schreibt den Durschnittswert vor Rückgabe auch noch in die lokale
Variable 'wert', was eigentlich überflüssig ist.

- main.c:
Die Routine zum Einlesen einer Zahl ist fehlerträchtig, da
die Länge der Zeichenkette nicht überprüft wird und die
Länge von hilfsarray mit 10 auch nicht gerade großzügig
bemessen ist. Einfacher und sicherer geht es mit fgets.
fgets sorgt dafür, dass nicht mehr Zeichen eingelesen werden
können, als durch den 'size'-Parameter vorgegeben wird
(genaugenommen wird ein Zeichen weniger eingelesen, da ja
noch ein Byte für die abschließende '0' gebraucht wird),
weiterhin gibt fgets NULL zurück, wenn ein EOF erreicht
wird oder der Benutzer Ctrl+D eingibt.
Die main-Routine würde damit so aussehen:


#include "durchschnitt.h"

int main(void)   {
        int arrayused=0;
        double array[MAX];
        char hilfsarray[20];
        while((arrayused<MAX) && fgets(hilfsarray, 20, stdin))
            array[arrayused++] = atof(hilfsarray);

        for (int i = 0; i < arrayused; i++)  {
                printf("Zahl %d: %f\n", i+1, array[i]);
        }
        printf("Durchschnitt: %f\n", durchschnitt(array, arrayused));
        return 0;
}



Viele Grüße

Andreas

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 12:26 Uhr von *Markus veröffentlicht.

> Hallo,
>
> »» $ gcc -c durchschnitt.c -o durchschnitt.o -std=c99
> »» $ ar rcs libdurchschnitt.a durchschnitt.o
> »» $ gcc -static durchschnitt.h Main.c -L. -ldurchschnitt -o Main_statisch -std=c99
>
> ich habe das hier mit gcc Version 4.3.2 und ar aus
> den binutils 2.1.18.20080103 mal genauso probiert und kann
> kein auffälliges Verhalten finden, d. h. der Durchschnitt
> wird - auch mit Verwendung der Library - korrekt ausgegeben.

Hmmm, ich werde abends mal nachsehen, welche gcc-Version ich daheim benutze. Oder eventuell sind irgendwo bestimmte Compilerflags gesetzt?

> - durchschnitt.h:
> Die Zeilen
>
>
> #define MAX 30
> #include <stdio.h>
> #include <stdlib.h>
>

>
> werden allesamt nur in main.c benötigt. Aus Code-Design-Aspekten
> würde ich diese Zeilen daher auch in main.c schreiben, zumal es
> ja auch sein kann, dass durchschnitt.h von anderen Codes
> eingebunden sind, die evtl. <stdio.h> etc. schon anderweitig
> inkludieren oder die andere Vorstellungen von MAX haben [...]

Dazu hätte ich sowieso eine Frage. Wie sieht das "korrekte" Design für C-Programme eigentlich aus? Für sinnvoll halte ich natürlich einen objektorientierten Ansatz, aber da müsste ich mich wiederum fragen, warum ich nicht gleich C++ verwende, wenn ich schon mit C C++, oder Java "simulieren" will.

Markus

C: Verlinken statischer Bibliothek führt zu falschem Ergebnis

Der folgende Beitrag wurde am 12. 06. 2009, 19:47 Uhr von *Markus veröffentlicht.

Hallo nochmals,

es scheint aus irgend einem Grund nun doch geklappt. Ich weiß nicht, welchen Blödsinn ich da wohl gestern getrieben habe.

Danke jedenfalls für eure Tipps.

Markus

© 1998-2013 SELFHTMLImpressumSoftware: Classic Forum 3.4