Forum: PC-Programmierung C - Function / Define / Macro / Obfuscated C ?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
1 lesenswert
nicht lesenswert
Hallo zusammen,

in einem mpeg-Decoder fand ich folgende Macro Funktion:
1
#include <stdint.h>
2
3
#ifndef cmuls
4
#define cmuls(dre, dim, are, aim, bre, bim) \
5
do { \
6
  int32_t tre; \
7
  (tre) = (int32_t)(((int64_t)(are)* (int64_t)(bre)-(int64_t)(aim)* (int64_t)(bim)) >> 31); \
8
  (dim) = (int32_t)(((int64_t)(are)* (int64_t)(bim)+(int64_t)(aim)* (int64_t)(bre)) >> 31); \
9
  (dre) = tre; \
10
} while (0)
11
#endif

Ich habe daraus folgendes Test-Programm gemacht:
1
#include <stdint.h>
2
3
#ifndef cmuls
4
#define cmuls(dre, dim, are, aim, bre, bim) \
5
do { \
6
  int32_t tre; \
7
  (tre) = (int32_t)(((int64_t)(are)* (int64_t)(bre)-(int64_t)(aim)* (int64_t)(bim)) >> 31); \
8
  (dim) = (int32_t)(((int64_t)(are)* (int64_t)(bim)+(int64_t)(aim)* (int64_t)(bre)) >> 31); \
9
  (dre) = tre; \
10
} while (0)
11
#endif
12
13
#ifndef Test1
14
#define Test1(dre) \
15
do { \
16
  (dre) = (dre)+1; \
17
} while (0)
18
#endif
19
20
int main()
21
{
22
  int32_t aa, a, b, c, d, e, f;
23
  a = 0x1C954; //117076;
24
  b = 0x520C;  //21004;
25
  c = 0x1C954; // 117076;
26
  d = 0x520C;  //21004;
27
  e = 0x6DC25403; // 1841452035;
28
  f = 0xBE2500CB; // 3190096075;    
29
  cmuls(a,b,c,d,e,f);
30
31
  aa = 0;
32
  Test1(aa); 
33
  int32_t ergebnis = aa; // Ergebnis 1
34
  return 0;
35
}

Ich sehe bei der Art eine Funktion zu definieren nur Nachteile außer 
dass sie vielleicht einen Bruchteil einer Sekunde schneller ist!!!


Jetzt meine Frage:

Gibt es irgendeineinen Grund eine Funktion so zu definieren ?

von Walter T. (nicolas)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Gibt es irgendeineinen Grund eine Funktion so zu definieren ?

Wenn alle Aufruf-Parameter zur Compilezeit konstant ist, wird aus dem 
Makro eine Konstante.

von (prx) A. K. (prx)


Bewertung
2 lesenswert
nicht lesenswert
Inline-Funktionen sind eleganter.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Inline-Funktionen sind eleganter.

Inline ist doch ein C++ Keyword oder?

von Timmo H. (masterfx)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> A. K. schrieb:
> Inline-Funktionen sind eleganter.
>
> Inline ist doch ein C++ Keyword oder?

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Timmo H. schrieb:
> Andreas V. schrieb:
>> A. K. schrieb:
>> Inline-Funktionen sind eleganter.
>>
>> Inline ist doch ein C++ Keyword oder?
> Nö

Sorry mein C ist ein bissl eingerostet. Liegt am Compiler bzw. an den 
Einstellungen. Ich kriege es jedenfalls nur als C++ compiliert...

Ich frage mich halt nur warum man solche "#define" Definitionen für 
Funktionen wie oben heute noch macht. Mal abgesehen davon dass der 
Debugger streikt.

: Bearbeitet durch User
von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
>
> Jetzt meine Frage:
>
> Gibt es irgendeineinen Grund eine Funktion so zu definieren ?

Da mpeg sicher auf diversen Plattformen laufen soll, ist das die 
Variante die auf noch so alten Compilern die Multiplikation von 
Komplexen Zahlen im Q1.31-Format inline ausführt.

von Jemand (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich frage mich halt nur warum man solche "#define" Definitionen für
> Funktionen wie oben heute noch macht. Mal abgesehen davon dass der
> Debugger streikt.

Weil wegen mehr schnell!!1
:^)

von Archeologe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie alt ist eigentlich die Library? Und wie alt ist der Programmierer?

Erster Verdacht ist doch - das stammt aus einer Zeit, als wir uns noch 
nicht auf die Optimierung von Funktionsaufrufen verlassen konnten.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Archeologe schrieb:
> Erster Verdacht ist doch - das stammt aus einer Zeit, als wir uns noch
> nicht auf die Optimierung von Funktionsaufrufen verlassen konnten.

Oder - wie oben schon erwähnt wurde - es soll auch auf Compilern, die 
aus dieser Zeit stammen, zu effizientem Code führen.

Andreas V. schrieb:
> Ich sehe bei der Art eine Funktion zu definieren nur Nachteile außer
> dass sie vielleicht einen Bruchteil einer Sekunde schneller ist!!!

Naja, wie oft wird sie denn aufgerufen? Wenn das z.B. im Dekoder für 
jeden Pixel mehrmals aufgerufen wird, ist das bei einem 4k-Video mit 
60fps schon verdammt viel. Da lohnt es sich ggf. auch,

> einen Bruchteil einer Sekunde

bei jedem Aufruf zu sparen!!!1einself-Ausrufezeichen

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Die Frage wäre dann: Spart man mit einem modernen Compiler wirklich 
Zeit?

von leo (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Die Frage wäre dann: Spart man mit einem modernen Compiler
> wirklich
> Zeit?

Bei #define: nie - sind ja nur Textersetzungen. Diese koennen zur 
besseren Lesbarkeit von Code beitragen.

Bei Assembler-Code in GCC habe ich vor ca. 15 Jahren aufgegeben 
haendisch einzugreifen (Tailcode-Opt., Loop-Unrolling, FP-Code, ...) 
kann der GCC inzwischen besser.
Bei anderen C-Compilern wird das ca. gleich sein.

leo

von Vn N. (wefwef_s)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Inline ist doch ein C++ Keyword oder?

Nein.

Walter T. schrieb:
> Wenn alle Aufruf-Parameter zur Compilezeit konstant ist, wird aus dem
> Makro eine Konstante.

Mit ganz, ganz viel Glück könnte dir der Compiler eine Funktion auch so 
optimieren.
In C++ gibts constexpr dafür.

Andreas V. schrieb:
> Die Frage wäre dann: Spart man mit einem modernen Compiler wirklich
> Zeit?

Eher nein, wobei es natürlich auch schrottige Compiler gibt.

von Vn N. (wefwef_s)


Bewertung
0 lesenswert
nicht lesenswert
leo schrieb:
> Bei #define: nie - sind ja nur Textersetzungen. Diese koennen zur
> besseren Lesbarkeit von Code beitragen.

Er meinte ja gegenüber Funktionsaufrufen. Da spart es tatsächlich,  wenn 
Funktionen nicht geinlined werden (z.B. mit -O0 kompiliert).

von leo (Gast)


Bewertung
0 lesenswert
nicht lesenswert
vn n. schrieb:
> (z.B. mit -O0 kompiliert).

Yep, bei unoptimiert stimmt das. Ich ging von -O{3,s} also von 
Produktionscode aus.

leo

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
vn n. schrieb:
> Andreas V. schrieb:
>> Inline ist doch ein C++ Keyword oder?
>
> Nein.

Um das etwas genauer zu erläutern: Es gibt in beiden Sprachen ein 
Schlüsselwort "inline", allerdings nicht ganz in der selben Bedeutung.

> Walter T. schrieb:
>> Wenn alle Aufruf-Parameter zur Compilezeit konstant ist, wird aus dem
>> Makro eine Konstante.
>
> Mit ganz, ganz viel Glück könnte dir der Compiler eine Funktion auch so
> optimieren.

So arg viel Glück braucht man nicht. Die Funktion muss nur inline sein, 
und sofern man keine LTO hat, muss sie an der Stelle des Aufrufs der 
Quellcode sichtbar sein. Und natürlich muss die Funktion auch dazu 
geeignet sein (also z.B. nicht rekursiv).

> In C++ gibts constexpr dafür.

Bei GCC kann man (sowohl in C, als auch in C++) ein Inlining erzwingen 
mit __attribute__((always_inline)).

> Andreas V. schrieb:
>> Die Frage wäre dann: Spart man mit einem modernen Compiler wirklich
>> Zeit?
>
> Eher nein, wobei es natürlich auch schrottige Compiler gibt.

Man braucht aber auch nicht mehr Zeit gegenüber einer Inline-Funktion.

von Vn N. (wefwef_s)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> So arg viel Glück braucht man nicht. Die Funktion muss nur inline sein,
> und sofern man keine LTO hat, muss sie an der Stelle des Aufrufs der
> Quellcode sichtbar sein. Und natürlich muss die Funktion auch dazu
> geeignet sein (also z.B. nicht rekursiv).

Grundsätzlich ja, aber da wär halt noch das Thema "Code für 
uralte/schrottige Compiler".
Aber ja, vielleicht ist auch einfach nur der Code schrottig. Wenn man 
schon sowas macht, um es z.B. auch exotischen Compilern recht zu machen, 
sollte man es zumindest in einem Kommentar vermerken.

Rolf M. schrieb:
> Man braucht aber auch nicht mehr Zeit gegenüber einer Inline-Funktion.

Korrekt.
Wobei inline ja "erst" (oh Gott wird man alt) mit C99 Standard wurde 
(vorher aber von diversen Compilern schon unterstützt wurde), womit wir 
wieder beim Thema uralte/schrottige Compiler wären.

von Timmo H. (masterfx)


Bewertung
0 lesenswert
nicht lesenswert
Per Makro kommt in besten Fall etwas Konstantes raus (z.B. x = 234). Mit 
Inline kann es auch dynamisch sein ( x = y*203). Wenn man mit -O2 (am 
schnellsten) kompiliert, dann werden Funktionen auch automatisch Inline 
kompiliert wenn es schneller ist. Aber ein Makro läuft durch den 
Präprozessor  und erzeugt dadurch im besten Fall etwas schnelleren Code 
wenn es sinnvoll eingesetzt wurde.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Ich habe noch mal die Varianten ausprobiert, weil ich mir nicht mehr 
sicher war wie sich das bei aktuellen Compilern verhält. Dazu schrieb 
ich folgenden Code (und ja es kommt immer das gleiche Ergebnis heraus):
1
#include<stdio.h>
2
#include<stdint.h>
3
#include<time.h> 
4
#include <windows.h>
5
6
#ifndef cmuls
7
#define cmuls(dre, dim, are, aim, bre, bim) \
8
do { \
9
  int32_t tre; \
10
  (tre) = (int32_t)(((int64_t)(are)* (int64_t)(bre)-(int64_t)(aim)* (int64_t)(bim)) >> 31); \
11
  (dim) = (int32_t)(((int64_t)(are)* (int64_t)(bim)+(int64_t)(aim)* (int64_t)(bre)) >> 31); \
12
  (dre) = tre; \
13
} while (0)
14
#endif
15
16
inline void cmuls2(int32_t* dre, int32_t* dim, int32_t* are, int32_t* aim, int32_t* bre, int32_t* bim)
17
{
18
  int32_t tre; 
19
  (tre) = (int32_t)(((int64_t)(*are)* (int64_t)(*bre)-(int64_t)(*aim)* (int64_t)(*bim)) >> 31); 
20
  (*dim) = (int32_t)(((int64_t)(*are)* (int64_t)(*bim)+(int64_t)(*aim)* (int64_t)(*bre)) >> 31); 
21
  (*dre) = tre; 
22
}
23
24
void cmuls3(int32_t* dre, int32_t* dim, int32_t* are, int32_t* aim, int32_t* bre, int32_t* bim)
25
{
26
  int32_t tre;
27
  (tre) = (int32_t)(((int64_t)(*are)* (int64_t)(*bre) - (int64_t)(*aim)* (int64_t)(*bim)) >> 31);
28
  (*dim) = (int32_t)(((int64_t)(*are)* (int64_t)(*bim) + (int64_t)(*aim)* (int64_t)(*bre)) >> 31);
29
  (*dre) = tre;
30
}
31
32
33
34
#ifndef Test1
35
#define Test1(dre) \
36
do { \
37
  (dre) = (dre)+1; \
38
} while (0)
39
#endif
40
41
inline int max2(int a, int b) 
42
{
43
  int z = a > b ? a : b;
44
  return z;
45
}
46
47
int main()
48
{  
49
  clock_t t1, t2;
50
  
51
  double diff1, diff2, diff3 = 0.0;
52
  int32_t a, b, c, d, e, f;
53
  a = 0x1C954; //117076;
54
  b = 0x520C;  //21004;
55
  c = 0x1C954; // 117076;
56
  d = 0x520C;  //21004;
57
  e = 0x6DC25403; // 1841452035;
58
  f = 0xBE2500CB; // 3190096075;    
59
  int maxCnt = 10000000;
60
61
  for (int nTests = 0; nTests < 100; nTests++)
62
  {
63
    a = 1;
64
    b = 2;
65
    c = 3;
66
    d = 4;
67
    e = 5;
68
    f = 6;
69
    t1 = clock();
70
    for (int x = 0; x < maxCnt; x++)
71
    {
72
      cmuls(a, b, c, d, e, f);
73
    }
74
    t2 = clock();
75
    diff1 = ((double)(t2 - t1) / CLOCKS_PER_SEC * 1000.0f);
76
    //printf("cmuls : %5u ms\n", (unsigned)diff1);
77
    //printf("%5u %5u %5u %5u %5u %5u\n", (unsigned)a, (unsigned)b, (unsigned)c, (unsigned)d, (unsigned)e, (unsigned)f);
78
79
80
81
    a = 1;
82
    b = 2;
83
    c = 3;
84
    d = 4;
85
    e = 5;
86
    f = 6;
87
    t1 = clock();
88
    for (int x = 0; x < maxCnt; x++)
89
    {
90
      cmuls2(&a, &b, &c, &d, &e, &f); // -1, 0, 3, 4, 5, 6    
91
    }
92
    t2 = clock();
93
    diff2 = ((double)(t2 - t1) / CLOCKS_PER_SEC * 1000.0f);
94
    //printf("cmuls2: %5u ms\n", (unsigned)diff2);
95
    //printf("%5u %5u %5u %5u %5u %5u\n", (unsigned)a, (unsigned)b, (unsigned)c, (unsigned)d, (unsigned)e, (unsigned)f);
96
97
98
    a = 1;
99
    b = 2;
100
    c = 3;
101
    d = 4;
102
    e = 5;
103
    f = 6;
104
    t1 = clock();
105
    for (int x = 0; x < maxCnt; x++)
106
    {
107
      cmuls3(&a, &b, &c, &d, &e, &f); // -1, 0, 3, 4, 5, 6
108
    }
109
    t2 = clock();
110
    diff3 = ((double)(t2 - t1) / CLOCKS_PER_SEC * 1000.0f);
111
    //printf("cmuls3: %5u ms\n", (unsigned)diff3);
112
    //printf("%5u %5u %5u %5u %5u %5u\n", (unsigned)a, (unsigned)b, (unsigned)c, (unsigned)d, (unsigned)e, (unsigned)f);
113
114
    double perc1 = diff1 / diff3 * 100.0;
115
    double perc2 = diff2 / diff3 * 100.0;
116
    double perc3 = 100.0f;
117
118
    printf("cmuls1: %03.2f \t", perc1);
119
    printf("cmuls2: %03.2f \t", perc2);
120
    printf("cmuls3: %03.2f \n", perc3);
121
122
    printf("");
123
  }
124
125
      return 0;
126
}

Ohne dass ich jetzt groß mit Compileroptionen herumspiele bekomme ich 
bei 100 Durchläufen mit jeweils 10 Mio. Berechnungen folgende 
Durchschnittswerte heraus:

 67,78% (Macro-Variante)

 67,01% (Inline-Variante)

100,00% (Nicht optimierter Code, immer langsamer)


Wobei die Prozentzahl die Ausführzeit im Verhältnis zum nicht 
optimierten Code angibt.

von Jemand (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> 67,78% (Macro-Variante)
>
>  67,01% (Inline-Variante)
>
> 100,00% (Nicht optimierter Code, immer langsamer)
>
> Wobei die Prozentzahl die Ausführzeit im Verhältnis zum nicht
> optimierten Code angibt.

Ich frage mich, wieso dein Compiler die Rechnungen überhaupt zur 
Laufzeit ausführen lässt. Mein GCC und Clang schmeißen die Rechnungen ab 
-O2 einfach komplett raus.

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Andreas V. schrieb:
>> 67,78% (Macro-Variante)
>>
>>  67,01% (Inline-Variante)
>>
>> 100,00% (Nicht optimierter Code, immer langsamer)
>>
>> Wobei die Prozentzahl die Ausführzeit im Verhältnis zum nicht
>> optimierten Code angibt.
>
> Ich frage mich, wieso dein Compiler die Rechnungen überhaupt zur
> Laufzeit ausführen lässt. Mein GCC und Clang schmeißen die Rechnungen ab
> -O2 einfach komplett raus.

Vermutlich passierte das bei obiger Messung in jedem Fall. 10^7 
Schleifendurchläufe dürften wohl nur dann fast genau so schnell sein wie 
(k)einer, wenn sie nicht passieren. Es ist eher so, daß -O0 50% länger 
für das Zeitmessen braucht. Statt der Messung würde ich erst mal
asm volatile "nop"
um die Schleifen packen und mir den generierten Code anschauen. Mehr als 
die Zuweisung von Konstanten an a und b wird da nicht stehen, wenn 
überhaupt.
Eher:
1
     NOP
2
     NOP

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Ich hätte auch den "Time"-Befehl verwenden können, aber dazu hätte ich 
den Test anders aufbauen müssen!...

Die Rechnungen wurden ausgeführt. Man könnte den Durchlauf einer 
Leerschleife abziehen, aber mir ging es hierbei nur darum eine 
Hausnummer zu bekommen was schneller ist....

: Bearbeitet durch User
von Jemand (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Die Rechnungen wurden ausgeführt.

Aber warum?

> mir ging es hierbei nur darum eine
> Hausnummer zu bekommen was schneller ist....

Welchen Compiler verwendest du überhaupt? Eine derart schlechte 
Verbesserung auf nur 67 % im Vergleich zum unoptimierten Maschinencode 
bekomme ich hier mit deinem Quellcode nicht nachgestellt. (oder der 
unoptimierte Maschinencode ist einfach krass gut)

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Welchen Compiler verwendest du überhaupt? Eine derart schlechte
> Verbesserung auf nur 67 % im Vergleich zum unoptimierten Maschinencode
> bekomme ich hier mit deinem Quellcode nicht nachgestellt. (oder der
> unoptimierte Maschinencode ist einfach krass gut)

In dem Fall nahm ich den:
   VC C/C++ Optimizing Compiler Version 18.00.21005.1 for x86

Ich kann es aber auch mal mit dem IAR für MSP mal ausprobieren:
   IAR 6.40.1

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Also beim IAR:
1
5 Messungen:
2
(Macro-Variante)  (Inline-Variante)  (nicht optimiert)  
3
68,8                   74,9             100
4
74,0                   71,8             100
5
98,6                   100              100
6
100,3                  97,85            100
7
106,9                  101,6            100
8
9
10
5 Messungen:
11
IAR mit Schalteroption Opimization High / Speed
12
(Macro-Variante)  (Inline-Variante)  (nicht optimiert)
13
98,2                  100,6             100
14
100,1                  97               100
15
99,8                   98,7             100
16
100,5                  99,6             100
17
105,7                  98,9             100

: Bearbeitet durch User
von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> (Macro-Variante)  (Inline-Variante)  (nicht optimiert)

Mit "nicht optimiert" meinst du die cmuls3 Funktion und nicht -O0?

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> Andreas V. schrieb:
>> (Macro-Variante)  (Inline-Variante)  (nicht optimiert)
>
> Mit "nicht optimiert" meinst du die cmuls3 Funktion und nicht -O0?

Ja. Ich meinte die Funktion cmuls3!

Ich wollte wissen ob es sich noch lohnt die Mühe zu machen den Code mit 
Macros oder Inline zu optimieren oder ob die Compiler das (notfalls mit 
der entsprechenden Compiler-Option) eigenständig machen.

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
1
 gcc -O1 testgcc.c
 hat es dann gebracht.

Unoptimiert brauchten sowohl gcc und VC jeweils ca. 1200ms für die 
Schleifen.
Die Macros und die Inline-Funktionen brachten in etwa die gleichen 
Ergebnisse wie in den Test zuvor.

Alle bekannten Compiler-Optionen brachten bei VC nicht viel. Das kenne 
ich von früher her anders...

Aber mit der o. g. Option -O1 beim gcc gings dann richtig ab.
15 ms sowohl für Makro-Funktion als auch für die Inline-Funktion.
Die Ergebnisse wurden berechnet.

Das erscheint mir ein bisschen schnell...

von Carl D. (jcw2)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
>
1
 gcc -O1 testgcc.c
 hat es dann gebracht.
>
> Unoptimiert brauchten sowohl gcc und VC jeweils ca. 1200ms für die
> Schleifen.
> Die Macros und die Inline-Funktionen brachten in etwa die gleichen
> Ergebnisse wie in den Test zuvor.
>
> Alle bekannten Compiler-Optionen brachten bei VC nicht viel. Das kenne
> ich von früher her anders...
>
> Aber mit der o. g. Option -O1 beim gcc gings dann richtig ab.
> 15 ms sowohl für Makro-Funktion als auch für die Inline-Funktion.
> Die Ergebnisse wurden berechnet.
>
> Das erscheint mir ein bisschen schnell...

Der Code sagt eigentlich nur: es wird jeweils n-mal die gleiche 
Berechnung durchgeführt, die ein konstantes Ergebnis hat, das noch nicht 
einmal weiterverwendet wird. Der Compiler muß noch nichtmal x auf den 
Wert cmax setzen, denn x existiert ja jeweils nur innerhalb der 
Schleifen. Die kürzestmögliche Übersetzung der Schleifen hat exakt 0 
Byte und jeder Compiler, der mehr daraus macht, ist nicht auf der Höhe 
der Zeit. Nicht umsonst gibt es mit volatile die Möglichkeit dem 
Compiler mitzuteilen, daß Dinge passieren können, die er nicht sehen 
kann.

N-mal konstante Werte beliebig kompliziert in ein nicht weiter 
interessierendes Ergebnis zu verrechnen sollte immer exakt 0 beliebige 
Zeiteinheiten dauern. Auch für sehr große N.

von S. R. (svenska)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> gcc -O1 testgcc.c  hat es dann gebracht.

Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?

von S. B. (piezokristall)


Bewertung
0 lesenswert
nicht lesenswert
>> Andreas V. schrieb:
>> gcc -O1 testgcc.c  hat es dann gebracht.
>
> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?
Erst einmal wäre für mich die Frage wofür "-O1" steht?
Laut manpages gcc Option für 'Level', was immer man sich darunter 
vorstellen darf - denn mehr findet man dort nicht.
Welche der rund 600 mehr oder weniger gut dokumentierten Optionen ist es 
denn nun?
https://www-user.tu-chemnitz.de/~hmai/gcc/Ausarbeitung_1/options.html

Weiterhin würde mich interessieren welche Compilerversion Du unter 
CodeBlocks benutzt?
Das alles 'Zufall' beim Compilieren und anschließender Ausführung sein 
soll, glaube ich nämlich nicht.

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
S. B. schrieb:
> Welche der rund 600 mehr oder weniger gut dokumentierten Optionen ist es
> denn nun?
> https://www-user.tu-chemnitz.de/~hmai/gcc/Ausarbeitung_1/options.html

Direkt an der Quelle wirds genauer als in Chemnitz:
https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Optimize-Options.html#Optimize-Options

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Der Code sagt eigentlich nur: es wird jeweils n-mal die gleiche
> Berechnung durchgeführt, die ein konstantes Ergebnis hat, das noch nicht
> einmal weiterverwendet wird. Der Compiler muß noch nichtmal x auf den
> Wert cmax setzen, denn x existiert ja jeweils nur innerhalb der
> Schleifen. Die kürzestmögliche Übersetzung der Schleifen hat exakt 0
> Byte und jeder Compiler, der mehr daraus macht, ist nicht auf der Höhe
> der Zeit. Nicht umsonst gibt es mit volatile die Möglichkeit dem
> Compiler mitzuteilen, daß Dinge passieren können, die er nicht sehen
> kann.
>
> N-mal konstante Werte beliebig kompliziert in ein nicht weiter
> interessierendes Ergebnis zu verrechnen sollte immer exakt 0 beliebige
> Zeiteinheiten dauern. Auch für sehr große N.

Ich habe noch einmal eine Operation hinzugefügt (are = are + 1;) und die 
Bit-Schiebeaktion weggelassen. Es sind jetzt so oder so keine 
Konstanten. Man sollte auch beachten dass die Parameter "Call by 
Reference" übergeben werden und nicht "Call by Value". Die Werte werden 
also weiterverwendet.

Die Zeitwerte haben sich nicht wesentlich geändert!
1
#ifndef cmuls
2
#define cmuls(dre, dim, are, aim, bre, bim) \
3
do { \
4
  int32_t tre; \
5
  are = are + 1; \
6
  (tre) = (int32_t)(((int64_t)(are)* (int64_t)(bre)-(int64_t)(aim)* (int64_t)(bim)) ); \
7
  (dim) = (int32_t)(((int64_t)(are)* (int64_t)(bim)+(int64_t)(aim)* (int64_t)(bre)) ); \
8
  (dre) = tre; \
9
} while (0)
10
#endif
11
12
inline void cmuls2(int32_t* dre, int32_t* dim, int32_t* are, int32_t* aim, int32_t* bre, int32_t* bim)
13
{
14
  int32_t tre; 
15
  *are = *are + 1;  
16
  (tre) = (int32_t)(((int64_t)(*are)* (int64_t)(*bre)-(int64_t)(*aim)* (int64_t)(*bim)) ); 
17
  (*dim) = (int32_t)(((int64_t)(*are)* (int64_t)(*bim)+(int64_t)(*aim)* (int64_t)(*bre)) ); 
18
  (*dre) = tre; 
19
}
20
21
void cmuls3(int32_t* dre, int32_t* dim, int32_t* are, int32_t* aim, int32_t* bre, int32_t* bim)
22
{
23
  int32_t tre;
24
  *are = *are + 1;
25
  (tre) = (int32_t)(((int64_t)(*are)* (int64_t)(*bre) - (int64_t)(*aim)* (int64_t)(*bim)) );
26
  (*dim) = (int32_t)(((int64_t)(*are)* (int64_t)(*bim) + (int64_t)(*aim)* (int64_t)(*bre)) );
27
  (*dre) = tre;
28
}

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-2 lesenswert
nicht lesenswert
S. R. schrieb:
> Andreas V. schrieb:
>> gcc -O1 testgcc.c  hat es dann gebracht.
>
> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?

Ich verwende solche Optionen mit Vorsicht. Da muss man aufpassen dass 
nichts wegoptimiert wird. In der Praxis würde ich so etwas nur verwenden 
wenn es nicht anders geht.
Ich kenne bessere Arten seine Zeit zu verbringen...

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> S. B. schrieb:
>> Welche der rund 600 mehr oder weniger gut dokumentierten Optionen ist es
>> denn nun?
>> https://www-user.tu-chemnitz.de/~hmai/gcc/Ausarbeitung_1/options.html
>
> Direkt an der Quelle wirds genauer als in Chemnitz:
> 
https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Optimize-Options.html#Optimize-Options

Und was bedeutet das für mich? Ab welcher Optimierung wird es unsinnig?

Eine Optimierung um das 1000-fache schneller. Da gibt es doch 
Nebeneffekte! Oder?

: Bearbeitet durch User
von mh (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Eine Optimierung um das 1000-fache schneller. Da gibt es doch
> Nebeneffekte! Oder?

Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.

Welche Regeln? ;-)

von (prx) A. K. (prx)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Eine Optimierung um das 1000-fache schneller. Da gibt es doch
> Nebeneffekte! Oder?

Wie man in den Wald reinruft, so schallt es zurück. Bei Testcode muss 
man drauf achten, dass es nicht ausreicht, den Compiler das Endergebnis 
selbst ermitteln zu lassen. Sonst setzt der dieses Endergebnis in den 
Code rein, nicht den Algorithmus.

Solche Optimierungen sind sinnvoller als mancher annimmt. Denn ein 
Nebeneffekt von Konstanten statt Variablen als Parameter solcher Makros 
oder Funktionen ist eine mögliche Vereinfachung der Berechnung. Das 
kommt in realem Code öfter vor und ist genauso richtig.

Ein weiterer Nebeneffekt ist, dass bei laut Standard nicht klar 
definiertem Ergebnis der Compiler etwas anders rechnen könnte als die 
Maschine.

: Bearbeitet durch User
von Christoph O. (lichtstrahl)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Das erscheint mir ein bisschen schnell...

Andreas V. schrieb:
> Da gibt es doch
> Nebeneffekte! Oder?

Es ist schon erstaunlich, wie moderne Compiler optimieren können!
Im Studium habe ich mal einen Equalizer in C implementiert, der bestand 
aus kaskadierten Filtern mit jeweils einigen Additionen/Multiplikationen 
pro Stufe.
Während ich selbst mit allen mir bekannten Tricks die Laufzeit im 
Vergleich zur nicht-optimierten Implementierung nur halbieren konnte, 
hat der gcc sie mit gesetztem Optimierungsflag auf unter 1% gedrückt.
Habe ich dann ungläubig dem Prof. gezeigt, er war aber wenig überrascht 
und meinte nur, dass vernünftige Compiler heutzutage besser optimieren 
als die meisten "Experten".

von Vincent H. (vinci)


Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Solche Optimierungen sind sinnvoller als mancher annimmt. Den ein
> Nebeneffekt von Konstanten statt Variablen als Parameter solcher Makros
> oder Funktionen ist eine mögliche Vereinfachung der Berechnung. Das
> kommt in realem Code öfter vor und ist genauso richtig.


Hier ein Beispiel über dass ich gestern gestolpert bin:

1
// The macros below are derived from the ones above and are used to
2
// check for more specific object types.
3
// Note: these are kept as macros because inline functions sometimes use much
4
// more code space than the equivalent macros, depending on the compiler.
5
6
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
7
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
8
#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str))
9
#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op))
10
#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function))

Folgende Zeilen stammen direkt aus dem MicroPython Repo:
https://github.com/micropython/micropython/blob/master/py/obj.h#L258

/edit
Man beachte das Kommentar!

: Bearbeitet durch User
von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> Andreas V. schrieb:
>> Eine Optimierung um das 1000-fache schneller. Da gibt es doch
>> Nebeneffekte! Oder?
>
> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.

Wenn ich dich bisher richtig verstanden habe, benutzt du die Sprache c. 
Du musst dich also an die Regeln der Sprache c halten?!?

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> mh schrieb:
>> Andreas V. schrieb:
>>> Eine Optimierung um das 1000-fache schneller. Da gibt es doch
>>> Nebeneffekte! Oder?
>>
>> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.
>
> Wenn ich dich bisher richtig verstanden habe, benutzt du die Sprache c.
> Du musst dich also an die Regeln der Sprache c halten?!?

Also ich kann mich daran erinnern dass da unter Umständen 
Typenprüfungen, Overflows usw. nicht mehr geprüft werden...

von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Also ich kann mich daran erinnern dass da unter Umständen
> Typenprüfungen, Overflows usw. nicht mehr geprüft werden...

Nur wenn du dich nicht an die Regeln hältst...

von Christoph O. (lichtstrahl)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Also ich kann mich daran erinnern dass da unter Umständen
> Typenprüfungen, Overflows usw. nicht mehr geprüft werden...

In C wird sowas üblicherweise vom Compiler und nicht zur Laufzeit 
geprüft.
Die Zeit, die für die Kompilierung benötigt wird, ist bei einem 
optimierenden Compiler vermutlich höher.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
Was kann man an so einfachen Berechnungen und Schleifen wegoptimieren 
außer Überprüfungen, Exceptions, ..?

von mh (Gast)


Bewertung
3 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Was kann man an so einfachen Berechnungen und Schleifen
> wegoptimieren
> außer Überprüfungen, Exceptions, ..?

Die ganze Schleife, wenn niemand das Ergebnis anguckt.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
>> Was kann man an so einfachen Berechnungen und Schleifen
>> wegoptimieren
>> außer Überprüfungen, Exceptions, ..?
>
> Die ganze Schleife, wenn niemand das Ergebnis anguckt.

Ganz genau!

von mh (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> mh schrieb:
>>> Was kann man an so einfachen Berechnungen und Schleifen
>>> wegoptimieren
>>> außer Überprüfungen, Exceptions, ..?
>>
>> Die ganze Schleife, wenn niemand das Ergebnis anguckt.
>
> Ganz genau!

Wo ist dann dein Problem? Die Aussagekraft deines "Benchmarks" geht auch 
gegen 0, wenn die Schleife nicht wegoptimiert wird.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> Wo ist dann dein Problem? Die Aussagekraft deines "Benchmarks" geht auch
> gegen 0, wenn die Schleife nicht wegoptimiert wird.

Ich habe mich nur gefragt warum man C-Macros verwendet, wenn es 
Inline-Funktionen und Compiler-Optionen gibt.

Das Macro ist nicht von mir und wahrscheinlich sehr alt. Außerdem 
gefällt mir die (Typen-)Deklaration/Definition nicht. Das do-while 
Konstrukt kann ich mir nur so erklären dass der Compiler es damals 
anders nicht genommen hat. Warum das Macro schnreller ist und kleiner im 
Code umgesetzt wird hängt meiner Meinung nach damit zusammen dass mit 
den Typen, Überläufen, Exceptions,... weniger strict verfahren wird.

Liege ich falsch?
1
#ifndef cmuls
2
#define cmuls(dre, dim, are, aim, bre, bim) \
3
do { \
4
  int32_t tre; \
5
  are = are + 1; \
6
  (tre) = (int32_t)(((int64_t)(are)* (int64_t)(bre)-(int64_t)(aim)* (int64_t)(bim)) ); \
7
  (dim) = (int32_t)(((int64_t)(are)* (int64_t)(bim)+(int64_t)(aim)* (int64_t)(bre)) ); \
8
  (dre) = tre; \
9
} while (0)
10
#endif

: Bearbeitet durch User
von (prx) A. K. (prx)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Das do-while
> Konstukt kann ich mir nur so erklären dass der Compiler es damals anders
> nicht genommen hat.

Bei
  #define MACRO(x) { ... }

  if (cond)
    MACRO(x);
  else
    unsinn();
gibts einen Syntaxfehler, weil das ";" zu viel ist. Bei
  #define MACRO(x) do{ ... }while(0)
passt es.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
A. K. schrieb:
> Andreas V. schrieb:
>> Das do-while
>> Konstukt kann ich mir nur so erklären dass der Compiler es damals anders
>> nicht genommen hat.
>
> Bei
>   #define MACRO(x) { ... }
>
>   if (cond)
>     MACRO(x);
>   else
>     unsinn();
> gibts einen Syntaxfehler, weil das ";" zu viel ist. Bei
>   #define MACRO(x) do{ ... }while(0)
> passt es.

Mir gehen Macros auch aufn Keks...

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
> Hier ein Beispiel über dass ich gestern gestolpert bin:
>
> // The macros below are derived from the ones above and are used to
> // check for more specific object types.
> // Note: these are kept as macros because inline functions sometimes use
> much
> // more code space than the equivalent macros, depending on the
> compiler.
>
> #define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) &&
> (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work
> for checking int, str or fun; use below macros for that
> #define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o,
> &mp_type_int))
...
> Man beachte das Kommentar!

Typensicherheit ADE!

Wenn ich so etwas sehe dann will ich mich nur noch erschießen...

von S. R. (svenska)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich habe mich nur gefragt warum man C-Macros verwendet, wenn es
> Inline-Funktionen und Compiler-Optionen gibt.

Ganz einfach - weil es Menschen gibt, die wie folgt denken:

Andreas V. schrieb:
>>> gcc -O1 testgcc.c  hat es dann gebracht.
>> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?
>
> Ich verwende solche Optionen mit Vorsicht.
> Da muss man aufpassen dass nichts wegoptimiert wird.
> In der Praxis würde ich so etwas nur verwenden
> wenn es nicht anders geht.

Konkret: Wenn du Optimierungen abschaltest, weil du Angst davor hast, 
dann bist du mit dem Makro deutlich besser dran als mit dem besten 
Compiler der Welt, denn du hast ihm ja die Optimierungen verboten.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
1 lesenswert
nicht lesenswert
Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen 
nachzuprüfen!
Es wäre nicht dass erste Mal dass eine Schleife wegoptimiert wird, oder 
...

von Nils P. (torus)


Bewertung
0 lesenswert
nicht lesenswert
> Ich frage mich halt nur warum man solche "#define" Definitionen für
> Funktionen wie oben heute noch macht. Mal abgesehen davon dass der
> Debugger streikt.

Das geht natürlich auch als Inline Function. Inline Functions werden 
allerdings wie normale Funktionen realisiert wenn man ohne Optimierungen 
compiliert.

Das ganze als Macro zu definieren erzwingt das inlining und kann dadurch 
auch im Debug Build eine akzeptable Geschwindigkeit erzielen.

Ja, das ist beim debuggen blöd, aber wenigstens hat man eine Chance zu 
debuggen.

von Rolf M. (rmagnus)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> S. R. schrieb:
>> Andreas V. schrieb:
>>> gcc -O1 testgcc.c  hat es dann gebracht.
>>
>> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?
>
> Ich verwende solche Optionen mit Vorsicht. Da muss man aufpassen dass
> nichts wegoptimiert wird. In der Praxis würde ich so etwas nur verwenden
> wenn es nicht anders geht.

Wenn was wegoptimiert wird, das eigentlich notwendig wäre, hat das 
Programm einen Fehler.

Andreas V. schrieb:
> mh schrieb:
>> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.
>
> Welche Regeln? ;-)

Na die von C.

Andreas V. schrieb:
> Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen
> nachzuprüfen!
> Es wäre nicht dass erste Mal dass eine Schleife wegoptimiert wird, oder
> ...

Wie gesagt: Dann ist eigentlich das Programm fehlerhaft, und du hast den 
Fehler durch Unterdrücken der Optimierungen nur versteckt. Das ist 
meiner Meinung nach keine gute Herangehensweise.

von S. R. (svenska)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen
> nachzuprüfen!

Also hast du Angst, dass der Compiler irgendwas mit deinem Code macht, 
was du nicht willst...

Andreas V. schrieb:
> Es wäre nicht dass erste Mal dass eine Schleife wegoptimiert
> wird, oder ...

...was bedeutet, dass dein Code schlicht fehlerhaft ist.
Oder bist du tatsächlich darauf angewiesen, dass überflüssige Schleifen 
in deinem Code tatsächlich zur Laufzeit ausgeführt werden müssen?

von Dr. Sommer (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen
> nachzuprüfen!

Dann lass dir doch vom Compiler helfen und schalte alle Optimierungen 
und Warnungen an. Wenn der Code dann nicht mehr funktioniert, ist er 
höchstwahrscheinlich falsch. Diese Fehler könnten ja auch mit neuen 
Compiler Versionen oder anderen Konstellationen auch ohne Optimierungen 
doch wieder auftreten.
Code, der nur ohne Optimierung funktioniert, würde ich nie produktiv 
nutzen - wer weiß wann einem diese Mine um die Ohren fliegt! Wenn 
offensichtlich Fehler drin sind, kann man das doch nicht so lassen.

von 900ss D. (900ss)


Bewertung
1 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Wenn was wegoptimiert wird, das eigentlich notwendig wäre, hat das
> Programm einen Fehler.

ACK! Ich habe sehr sehr selten bis nie ein Problem mit der Optimierung. 
Ohne die wären einige Projekte garnicht vernünftig gelaufen weil einfach 
keine Rechenzeit übrig war in Peak-Situationen. Gut das ist auch etwas, 
was einem die Nase kraus werden lässt, ging aber nicht mehr anders. Oder 
ein Requirement dass eine CPU-Load von xx% nicht überschritten werden 
darf,  hätte sonst nicht eingehalten werden können.

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
Ich habe eben folgende Zeilen im bzip2 Code gefunden:
1
static
2
int bz_config_ok ( void )
3
{
4
   if (sizeof(int)   != 4) return 0;
5
   if (sizeof(short) != 2) return 0;
6
   if (sizeof(char)  != 1) return 0;
7
   return;
8
}

Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2) gibt die 
Funktion immer 0 zurück.

sizeof(int) ergibt 0!

Ich kann also nicht mehr zippen!
;-)

von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2) gibt die
> Funktion immer 0 zurück.

Was sollte diese Funktion deiner Meinung nach zurück geben?

von 900ss D. (900ss)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> sizeof(int) ergibt 0!

Hmmm.... das halte ich für ein Gerücht.

Außerdem ist der return-Wert beim letzten Return undefiniert.
Die Routine ist buggy.

von Dirk K. (merciless)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich habe eben folgende Zeilen im bzip2 Code gefunden:
>
>
1
> static
2
> int bz_config_ok ( void )
3
> {
4
>    if (sizeof(int)   != 4) return 0;
5
>    if (sizeof(short) != 2) return 0;
6
>    if (sizeof(char)  != 1) return 0;
7
>    return;
8
> }
9
>
>
> Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2) gibt die
> Funktion immer 0 zurück.
>
> sizeof(int) ergibt 0!
>
> Ich kann also nicht mehr zippen!
> ;-)
Die Zeile
1
  return;
Sollte eine Warnung/einen Fehler produzieren.
Wenn nicht, solltest du die Compilerflags prüfen.

merciless

: Bearbeitet durch User
von Vn N. (wefwef_s)


Bewertung
1 lesenswert
nicht lesenswert
900ss D. schrieb:
> Außerdem ist der return-Wert beim letzten Return undefiniert.
> Die Routine ist buggy.

Offensichtlich hat er den Code fehlerhaft abgetippt (Copy&paste 
anyone?), denn das Original lt. Sourceforge sieht anders aus:
1
static
2
int bz_config_ok ( void )
3
{
4
   if (sizeof(int)   != 4) return 0;
5
   if (sizeof(short) != 2) return 0;
6
   if (sizeof(char)  != 1) return 0;
7
   return 1;
8
}

Schnell überflogen ist rätselhaft, was da wegoptimiert werden soll.

Andreas V. schrieb:
> sizeof(int) ergibt 0!

Mit Sicherheit nicht. Woher nimmst du diese Weißheit?

Andreas V. schrieb:
> Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2)

O1 und O2 ist beides auf Geschwindigkeit. Os ist Codegröße, beim GCC 
jedenfalls.

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
sorry das "return 1;" ist irgendwie beim Kopieren verlorengegangen. Da 
hätte der Compiler schon angeschlagen;

Es funzt trotzdem nicht.

/O1 (auf Größe optimiert)

/O2 (auf Geschwindigkeit optimiert)

zumindest ist das beim VC so.

: Bearbeitet durch User
von 900ss D. (900ss)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Es funzt trotzdem nicht.

Und wie prüfst du das genau das die Funktion nicht funktioniert?

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
sizeof(int) ergibt 0 statt 4!

von 900ss D. (900ss)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> /O2 (auf Geschwindigkeit optimiert)

Und das stimmt nicht, es ist auch eine Laufzeitoptimierung.
Wie schon jemand Schritten -Os ist "för speed".

von 900ss D. (900ss)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> sizeof(int) ergibt 0 statt 4!

Woran erkennst du das?

von 900ss D. (900ss)


Bewertung
0 lesenswert
nicht lesenswert
900ss D. schrieb:
> Wie schon jemand Schritten

 sollte natürlich heißen
Wie schon jemand schrieb

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Ich habe es mir im Debugger mit und ohne Optimierung ausgeben lassen.

: Bearbeitet durch User
von S. R. (svenska)


Bewertung
2 lesenswert
nicht lesenswert
vn n. schrieb:
> Schnell überflogen ist rätselhaft, was da wegoptimiert werden soll.

Der Compiler kann sämtliche sizeof() zur Compilezeit ausrechnen und dann 
die gesamte Funktion wegoptimieren.

Auf manchen Architekturen (z.B. AVR) ist sizeof(int) == 2, dann gibt die 
Funktion immer 0 zurück. Alle auch nur ansatzweise üblichen 
Architekturen, wo das nicht der Fall ist, haben sizeof(int) == 4.

Wenn da was anderes rauskommt, ist höchstwahrscheinlich der Compiler 
kaputt.

Aber ich glaube, der TO will uns nur ein (doofes) Beispiel für "der 
Compiler optimiert meine Funktion weg und das will ich nicht" zeigen. 
Was natürlich schon in sich relativ bescheuert ist, aber das ist ja 
nicht mein Problem.

von 900ss D. (900ss)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich habe es mir im Debugger ausgeben lassen.

Also du bist schrittweise durch die Funktion gesteppt?
Wenn du den Compiler optimieren läst, dann passen die 
Zeileninformationen nicht mehr zum Sourcecode und es kommt erstmal 
wirres beim debuggen raus.
Du müsst dir das Ergebnis von der Funktion mit printf oder sonst wie 
ausgeben lassen.

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
Also habe ich auf einem X86 (32 Bit) ein Sizeof(int) von 0. Will heißen 
ich habe viel Speicher gespart / optimiert!

von 900ss D. (900ss)


Bewertung
1 lesenswert
nicht lesenswert
Oder bau dir eine Zeile ein

printf("%d\n", sizeof(int));

Dann siehst du die Größe von int auf deinem Rechner.

von Fädel Mädel (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> A. K. schrieb:
>> Inline-Funktionen sind eleganter.
>
> Inline ist doch ein C++ Keyword oder?

Njein,

"inline" ist relativ neu im C-Standard; es wurde eingeführt in "section 
6.7.4 of the C99 standard (ISO/IEC 9899:1999)". Verschiedene Compiler 
wie der gcc kannten es schon bevor es Standard wurde (1999).

Da MPEG aber älter ist (1991), könnte das der Grund sein, warum man sich 
für die unelegantere aber steinzeitkompatiblevariante entschied. Falls 
es mangels der "inline"-Unterstützung der damaligen Compiler überhaupt 
eine Entscheidungsmöglichkeit gab.

von S. R. (svenska)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Also habe ich auf einem X86 (32 Bit) ein Sizeof(int) von 0.
> Will heißen ich habe viel Speicher gespart / optimiert!

Nö, du hast nur deine Unfähigkeit bescheinigt.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
;-)

von vn nn (Gast)


Bewertung
0 lesenswert
nicht lesenswert
S. R. schrieb:
> Der Compiler kann sämtliche sizeof() zur Compilezeit ausrechnen und dann
> die gesamte Funktion wegoptimieren.

Natürlich kann er das, aber es erklärt nicht warum es dann nicht 
funktionieren soll, so war das gemeint.

S. R. schrieb:
> Auf manchen Architekturen (z.B. AVR) ist sizeof(int) == 2, dann gibt die
> Funktion immer 0 zurück. Alle auch nur ansatzweise üblichen
> Architekturen, wo das nicht der Fall ist, haben sizeof(int) == 4.

Klar, wobei das eine denkbar doofe Lösung ist, könnte man seit C99 
immerhin auch einfach uint32_t nehmen.

S. R. schrieb:
> Aber ich glaube, der TO will uns nur ein (doofes) Beispiel für "der
> Compiler optimiert meine Funktion weg und das will ich nicht" zeigen.
> Was natürlich schon in sich relativ bescheuert ist, aber das ist ja
> nicht mein Problem.

Vermutlich, oder er will einfach nur trollen.

von Macker (Gast)


Bewertung
0 lesenswert
nicht lesenswert
vn n. schrieb:
> Er meinte ja gegenüber Funktionsaufrufen. Da spart es tatsächlich,  wenn
> Funktionen nicht geinlined werden (z.B. mit -O0 kompiliert).

Es es nicht nur der Aufruf der Funktion, der Compiler kann dann besser 
optimieren. Das gilt sowohl für Makros und für inline.

von vn nn (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Natürlich kann er das, aber was hat das mit meinem Posting zu tun?
Die Sache mit dem Macro ist drinnen weil damals Compiler oftmals nicht 
mal inlinen konnten, da brauchte man über weitergehende Optimierungen 
nicht mal nachdenken. Dass er das heute schon kann, wurde ja schon zu 
genüge geklärt.

von Rolf M. (rmagnus)


Bewertung
1 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich habe es mir im Debugger mit und ohne Optimierung ausgeben lassen.

Gib es mit z.B. printf aus. Die Ausführung von optimiertem Code im 
Debugger hat ihre Tücken.

von 900ss D. (900ss)


Bewertung
2 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Gib es mit z.B. printf aus.

Hatte ich oben ja schon vorgeschlagen.

Er weiss es besser und glaubt es nicht. Dabei ist das wirklich die 
einfachste Art, dass zu prüfen. Lass ihn weiter alles besser wissen :)

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Gib es mit z.B. printf aus. Die Ausführung von optimiertem Code im
> Debugger hat ihre Tücken.

Ich lache mich tot.
Ich hatte vorher schon einen kompletten cleanup gemacht und alles neu 
kompiliert. Es funzte nicht.

Nur wenn ich die Werte mit printf ausgebe springt das Programm nicht zum 
Exit. Ist halt nur blöd wenn man mal ein Gerät hat das kein printf 
kennt.

Ja schon klar über serial Port, aber denn will man ja vielleicht 
nicht....

Die IDE war mir abgestürzt...

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ist halt nur blöd wenn man mal ein Gerät hat das kein printf kennt.

sprintf() und dann den Puffer im Debugger angucken.

von 900ss D. (900ss)


Bewertung
2 lesenswert
nicht lesenswert
Du bist schon mehrere Male darauf hinwiesen worden, dass das debuggen 
von optimiertem Code wirre Sachen ergeben kann. Glaub es einfach.

von 900ss D. (900ss)


Bewertung
0 lesenswert
nicht lesenswert
moin Jörg :)

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
-1 lesenswert
nicht lesenswert
.. und dann noch ein #IFDEF DEBUG drumherum! :-)

von Rolf M. (rmagnus)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Rolf M. schrieb:
>> Gib es mit z.B. printf aus. Die Ausführung von optimiertem Code im
>> Debugger hat ihre Tücken.
>
> Ich lache mich tot.
> Ich hatte vorher schon einen kompletten cleanup gemacht und alles neu
> kompiliert. Es funzte nicht.
>
> Nur wenn ich die Werte mit printf ausgebe springt das Programm nicht zum
> Exit. Ist halt nur blöd wenn man mal ein Gerät hat das kein printf
> kennt.
>
> Ja schon klar über serial Port, aber denn will man ja vielleicht
> nicht....

Es ist doch ganz einfach: Wenn du ein sizeof(int) machst, es aber 
nirgends im Programm benutzt, dann ist es nutzlos und wird vom Compiler 
wegoptimiert. Sobald du es auch benutzt, passiert das natürlich nicht 
mehr. Der Optimizer ist ja gerade dafür da, alles rauszuwerfen, was 
nicht benötigt wird. Deshalb kommt natürlich auch Blödsinn raus, wenn du 
Code schreibst, dessen Ergebnis du im Programm gar nicht benutzt und 
dann im Debugger anschaust, welcher Wert rauskommt. Für das Programm 
spielt der Wert keine Rolle, da es ihn sowieso verwirft. Baust du das 
printf ein, dann wird der Wert benötigt, da er ja ausgegeben werden 
muss, also kann er nicht mehr wegoptimiert werden.

von Andreas V. (Firma: IGL) (andreas_va)


Bewertung
0 lesenswert
nicht lesenswert
Dann kann ich bz_config_ok ja auskommentieren.

von 900ss D. (900ss)


Bewertung
0 lesenswert
nicht lesenswert
Bau das printf einfach an eine andere Stelle im Code ein. So hatte ich 
es auch gemeint. In der Funktion bz_config_ok ... da hat Rolf schon 
Recht.
Und was gibt printf dir aus? :)

: Bearbeitet durch User
von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Dann kann ich bz_config_ok ja auskommentieren.

Wenn du das Ergebnis eh nicht verwendest, klar. Dann ändert sich dadurch 
ja auch am Programmablauf nix.

von S. R. (svenska)


Bewertung
3 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Ich lache mich tot.

Hör auf zu trollen.

Du erzeugst absichtlich Fehler, um uns dann weismachen zu wollen, dass 
optimierter Code fehlerhaft ist. Dabei bist du es, der den Unsinn 
verzapft.

von Dr. Sommer (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Andreas V. schrieb:
> Dann kann ich bz_config_ok ja auskommentieren.

Oder direkt zur Compile-Zeit prüfen:
1
#include <assert.h>
2
3
static_assert (sizeof(int) == 4, "Int muss 4 bytes sein");
4
static_assert (sizeof(short) == 2, "Short muss 2 bytes sein");
5
static_assert (sizeof(char) == 1, "Char muss 1 bytes sein");

Die letzte Prüfung ist natürlich sinnlos - sizeof(char) ist immer 1, 
auf jeder Plattform. Die Einheit, in der sizeof die Größe zurückgibt, 
sind Vielfache von der Größe von char - und 1 char ist nunmal genau 1 
char groß.

Noch besser ist aber natürlich auch die Verwendung von (u)int16_t und 
(u)int32_t. sizeof() übrigens gibt nie 0 zurück.

von Vn N. (wefwef_s)


Bewertung
1 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Die letzte Prüfung ist natürlich sinnlos - sizeof(char) ist immer 1,
> auf jeder Plattform. Die Einheit, in der sizeof die Größe zurückgibt,
> sind Vielfache von der Größe von char - und 1 char ist nunmal genau 1
> char groß.

Höchstens einen kaputten Compiler könnte man damit noch detektieren, 
aber so dermaßen kaputt wird wohl keiner sein.

Dr. Sommer schrieb:
> Noch besser ist aber natürlich auch die Verwendung von (u)int16_t und
> (u)int32_t.

Heute (damals gab es die vielleicht noch nicht, je nachdem von wann der 
Code ist) wäre dies sogar die einzig sinnvolle Variante.
Denn der Code macht dies ja vermutlich um sicherzustellen dass char == 
8bit, short == 16bit und int == 32bit ist. Blöderweise gibt es aber auch 
Plattformen auf denen gilt char == 16bit (für so eine schreib ich 
gerade). Wäre dort short == 32bit und int == 64bit (sind sie in meinem 
konkreten Fall nicht, wäre aber durchaus denkbar) wäre die Bedingung der 
sizeofs trotzdem erfüllt.

von Dr. Sommer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
vn n. schrieb:
> Wäre dort short == 32bit und int == 64bit (sind sie in meinem
> konkreten Fall nicht, wäre aber durchaus denkbar) wäre die Bedingung der
> sizeofs trotzdem erfüllt.

Richtig. Daher muss man zusätzlich prüfen ob CHAR_BIT = 8 ist. Das wäre 
deutlich sinnvoller als sizeof(char)=1 zu prüfen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.