Forum: Mikrocontroller und Digitale Elektronik Verbraucht ein struct mehr Platz als einzelne Variablen?


von Frank (Gast)


Lesenswert?

Hi Leute!

Der Betreff sagt eigentlich schon alles - wenn ich mehrere Dateien in 
einem struct zusammen fasse, verbraucht dieses dann insgesamt mehr 
Speicher als einzelne Variablen?

Und wie verhält es sich mit Variablen, die ich in einer externen Datei 
habe - entsteht beim Verweis durch "extern" irgendwie noch 
Speicherbedarf?

Hintergrund ist, dass ich extrem wenig Platz habe und alles damit so 
klein wie möglich machen möchte.

Habe schon alles Divisionen durch Subtraktionen ersetzt und arbeite auch 
mit Zahlen wie 10000% anstatt 100.00% und teile (bzw. subtrahiere danach 
wieder, um den richtigen Wert zu erhalten).

Gruß

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Grundsätzlich braucht eine struct nicht mehr Platz als die enthaltenen 
Variablen. Allerdings kann es, je nach Prozessor, nötig sein, z.B. 
1-Byte-Variable auf gerade Adressen zu setzen (alignment), was natürlich 
Platz kostet.
Ein weiterer Grund für insgesamt mehr Platzbedarf des Programms kann der 
Zugriff auf die Daten sein. Je nach Compiler und Optimierungsstufe kann 
das massive Auswirkungen auf den Code haben. Das gilt z.B. auch für 
Deine Frage zu extern.
Grüße, Kurt

von Frank (Gast)


Lesenswert?

OK, vielen Dank schonmal!

Aber dann muss ich doch mal fragen, wie man es am besten löst...

Ich möchte natürlich gerne ein wenig Ordnung im Programm haben, daher 
auch Variablen, die zum ADC gehören, dort im .c und .h File lassen. Auf 
diese muss ich aber von außen zugreifen können.

Also kann ich

a) Die Variablen als extern definieren

b) Funktionen schreiben, mit denen man auf sie zugreifen kann 
(wahrscheinlich die eleganteste Lösung)

c) alles global deklarieren, was ja aber irgendwie mit a) gleichkommt

Die Frage ist jetzt, was tendenziell mehr Speicher frisst. Ich kann es 
jetzt ausprobieren, aber dafür muss ich alles umschreiben. Sofern mir 
jemand eine Tendenz sagen kann, so würde ich mich ggf. daran machen.

Alles umschreiben und dann isses schlechter, ist natürlich blöd.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Hallo Frank,
Frank schrieb:
> a) Die Variablen als extern definieren
Keine schlechte Lösung, auch wenn b. eleganter ist. Alternative: 
inline-Funktionen.
> b) Funktionen schreiben, mit denen man auf sie zugreifen kann
> (wahrscheinlich die eleganteste Lösung)
Stimmt, so macht man das :-). Aber bei Platznot darf man auch mal den 
Pfad der Tugend verlassen.
> c) alles global deklarieren, was ja aber irgendwie mit a) gleichkommt
Stimmt, a == c :-).
Wenn ich wirklich Platzprobleme hatte, habe ich mir immer die Zeit 
genommen, z.B. zu vergleichen, ob der Zugriff auf eine struct per Zeiger 
kleineren Code ergibt, als der Einzelzugriff. Insbesondere, wenn ein 
Array von struct war. Mein Tipp, auch wenn es mühsam scheint: 
Codeinspection, also den erzeugten Assemblercode anschauen.
Wenn es aber den prozessor auch mit mehr Speicher gibt, und keine 
Timingeinschränkungen bestehen (kurzer Code), dann einfach die nächste 
Größe des Prozessors nehmen, das macht einfach mehr Spass.
Grüße, Kurt

von Frank (Gast)


Lesenswert?

Hallo Kurt und danke für deine Rückmeldung!

Ich werde wohl nicht drum herum kommen, es Schritt für Schritt zu 
testen. Danach ist man schlauer - auch für die Zukunft.

Kurt Harders schrieb:
> Wenn es aber den prozessor auch mit mehr Speicher gibt, und keine
> Timingeinschränkungen bestehen (kurzer Code), dann einfach die nächste
> Größe des Prozessors nehmen, das macht einfach mehr Spass.

Da gebe ich dir vollkommen recht. Beschränken tut mich aber eher, dass 
der Controller, den ich grad verwende, nahezu der einzige aus seiner 
Sparte ist, dessen ADC 16Bit differentiell misst (MSP430F2013)...auch 
wenn von den 16Bit nicht alle übrig bleiben...:\ aber sonst ist kein 
vergleichbares Derivat vorhanden, dass so klein, günstig und vielseitig 
ist.

Ich habe leider nicht nur wenig Platz im uC, sondern auch auf der 
Platine. Auf ein analoges Front-End würde ich im Idealfall daher gerne 
verzichten :O Differentielle ADCs sind in uCs ja leider selten 
vertreten.

von Marwin (Gast)


Lesenswert?

Einfach alle .c-Files in ein File includen und nur dieses uebersetzen. 
Dann kann der Compiler wirklich ueber den ganzen Code hinweg optimieren. 
Dann kann man auch ohne Kosten fuer Alles ordentliche Getter- und 
Setter-Funktionen verwenden und auf Pfusch mit globalen Variablen 
verzichten.

von Frank (Gast)


Lesenswert?

So, hab jetzt mal teilweise die globalen Variablen durch Setter und 
Getter ersetzt und bekomme knapp 100b mehr Code...:-\ Dafür habe ich 2b 
an RAM gespart. Damn

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Hallo Marwin,
Marwin schrieb:
> Einfach alle .c-Files in ein File includen und nur dieses uebersetzen.
> Dann kann der Compiler wirklich ueber den ganzen Code hinweg optimieren.
> Dann kann man auch ohne Kosten fuer Alles ordentliche Getter- und
> Setter-Funktionen verwenden und auf Pfusch mit globalen Variablen
> verzichten.
Dieses Vorgehen ist dann inlining aller funktionen :-). Allerdings mit 
dem Vorteil, dass der Compiler entscheiden kann, ob er das inlining zu 
Gunsten eines Funktionsaufrufs nicht ausführt. Damit ist diese Lösung 
sicher eine, die dem Compiler die besten Chancen gibt, seine Arbeit 
ordentlich zu tun :-).
Globale Variable halte ich genau dann nicht für Teufelswerk, wenn die 
Information wirklich global sein soll. Als "better-getter" :-) sind sie 
böse :-).
Grüße, Kurt

von Frank (Gast)


Lesenswert?

Aber bläst inline nicht auch den Code auf? Inline ist doch eher für 
Geschwindigkeitszuwachs.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Wenn der Compiler gut ist, und die Flags richtig gesetzt sind 
(Platzoptimierung) kann er die Entscheidung inline/out-of-line selbst 
treffen, wenn er, wie Marwin vorschlägt, den gesamten Code kennt.
Gerade bei getter/setter-Funktionen in getrennten Quelldateien kann das 
Registerhandling für den Funktionsaufruf richtig teuer werden.
Grüße, Kurt

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Vergiss die Tipps.

Befor du optimierst, schaust du dir an, was zu optimieren ist und ob 
dazu notwendigkeit besteht.

Bevor das geschehen ist, sind alle "Optimierungsstrategien" wie "Include 
alle C-Files" Käse und reine 100% Spekulation.

von Marwin (Gast)


Lesenswert?

Johann L. schrieb:

> Vergiss die Tipps.

...von gjlayde, denn sie sind...

> reine 100% Spekulation.

Es ist ziemlicher Bloedsinn viel Zeit in Analyse und Detailoptimierungen 
zu stecken mit denen man auch noch viele Kompromisse bezueglich der 
Codestruktur und -organisation eingehen muss, wenn man 90% der Wirkung 
durch einen simplen Trick bekommen kann, der den bei C leider 
vorhandenen Mangel, nicht richtig ueber Objektgrenzen hinweg optimieren 
zu koennen, umgeht.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Hallo Johann,
volle Zustimmung! Ich hatte Frank so verstanden, dass er die 
Platzprobleme schon hat. Sonst gelten die klassischen 
Optimierungsregeln:
Find a better algoritm
Don't do it.
Don't do it yet.
Use an optimising compiler.

Der letzten Regel versuchen wir gerade Substanz zu geben :-)
Grüße, Kurt

von Masl (Gast)


Lesenswert?

Die Variante mit dem dicken *.c File ist sicher die sparsamste, denn der 
Compiler weiß so wirklich über alles Bescheid.

Allerdings verletzt du dadurch die goldene Regel: "Keine *.c Files 
includen".

Wenn du aber weist, was du da machst, ist das kein Problem.

von Frank (Gast)


Lesenswert?

Kennt einer die Sysntax, bzw. wo überhaupt man beim IAR die Optimierung 
einschalten kann?

von Frank (Gast)


Lesenswert?

Kurt Harders schrieb:
> Ich hatte Frank so verstanden, dass er die
> Platzprobleme schon hat.

Ich habe noch ein wenig Platz, aber ich sehe halt, dass es eng wird - 
der Controller hat gerade mal 2k und 128b RAM.

Ich muss dazu sagen, dass ich jetzt nicht der super-Programmierer bin. 
Ich komme zurecht mit dem, was ich vorhabe und kann es auch immer 
umsetzen, nur halt nicht unbedingt 100% optimiert. Sonst hatte ich immer 
größere Controller, da war das nicht so schlimm, jetzt muss ich halt mal 
ein wenig mehr drauf achten - aber das ist ja auch OK, man lernt ja 
draus.

Schaut euch mal bitte mein Beispiel an - ich habe beispielsweise eine .h 
und .c für meine ADC-Geschichten.

Die .c:
1
// adc_functions.h
2
3
#ifndef ADC_FUNCTIONS_H
4
#define ADC_FUNCTIONS_H
5
6
#include <stdint.h>
7
8
#define ADC_REPEAT_CYCLES 32
9
10
struct adc
11
{
12
  volatile uint8_t  repeat_counter;
13
  volatile uint32_t average_sum;
14
  volatile uint8_t  new_measurement;
15
           uint16_t adc_result;
16
           uint16_t adc_lower_value;
17
           uint16_t adc_upper_value;
18
           uint16_t adc_span;
19
};
20
21
extern struct adc adc_control;
22
23
void adc_calc_result( void );
24
25
#endif // ADC_FUNCTIONS_H
und die .h:
1
// adc_functions.c
2
3
#include "adc_functions.h"
4
#include "msp430x20x3.h"
5
6
struct adc adc_control = { 0, 0, 0, 0, 0, 0, 0 };
7
8
void adc_calc_result( void )
9
{
10
  // 32 samples taken - build average by shifting sum right by 5
11
  adc_control.adc_result = ( adc_control.average_sum >> 5 );
12
13
  adc_control.average_sum = 0;                // Reset average
14
  adc_control.repeat_counter = 0;             // Reset repeat counter
15
  adc_control.new_measurement = 0;            // Reset flag
16
  SD16CCTL0 |= SD16SC;                        // Start new conversion
17
}
Dann in der main:
1
...
2
#include "adc_functions.h"
3
...
4
5
void main( void )
6
{
7
  // Stop watchdog timer to prevent time out reset
8
  WDTCTL = ( WDTPW | WDTHOLD );
9
10
 ...
11
    if( adc_control.new_measurement )
12
    {
13
      adc_calc_result();
14
    }
15
  ...
16
}
ISR greift auch drauf zu:
1
#pragma vector = SD16_VECTOR
2
__interrupt void SD16ISR( void )
3
{
4
  if( SD16IV == 4 )
5
  {
6
    adc_control.repeat_counter++;
7
    adc_control.average_sum += SD16MEM0;
8
    
9
    if( adc_control.repeat_counter < ADC_REPEAT_CYCLES )
10
    {
11
      SD16CCTL0 |= SD16SC;
12
    }
13
    else
14
    {
15
      adc_control.new_measurement = 1;
16
    }
17
  }
18
}

IST HALT ALLES ÜBER DIE GLOBALEN VARIABLEN

Wie kann man es jetzt besser machen? Wie gesagt, Funktion zum Setzen und 
Abholen der Variablen habe ich probiert, verbraucht mehr Platz.

Masl schrieb:
> Die Variante mit dem dicken *.c File ist sicher die sparsamste, denn der
> Compiler weiß so wirklich über alles Bescheid.

OK, das halte ich mir mal als letzte Option offen - versuche natürlich 
erstmal die elegantere Variante...sofern möglich.

Über Kritik freue ich mich ;-P

von Marwin (Gast)


Lesenswert?

Masl schrieb:

> Allerdings verletzt du dadurch die goldene Regel: "Keine *.c Files includen".

Wie die meisten der "goldenen Regeln" ist auch diese einfach Unsinn. Die 
wird aber leider von unzaehligen Anfaengern weitertransportiert, die 
voellig verdutzt gucken, wenn du ihnen verraetst, dass ein File das 
inkludiert wird, gar nicht .h heissen muss. Es muss noch nicht mal ein 
komplettes, fuer sich selbst uebersetzbares Stueck C im File sein.

von Frank (Gast)


Lesenswert?

Mist, .c und .h vertauscht, aber ich denke, es ist ersichtlich

von Simon K. (simon) Benutzerseite


Lesenswert?

C-Files zu inkludieren würde ich nur als echte Notlösung ansehen. Und 
zwar derart "notlösig", dass ich sie noch nie benötigt habe.

Die Methode hat nämlich einen riesen Haken: Du kannst jedes .c File nur 
ein mal inkludieren. Und damit zerstört man sich jegliches 
Programmierkonzept ("modulare Programmierung"). Und gerade das Konzept 
ist das, was Programmieren ausmacht.

von Oliver (Gast)


Lesenswert?

Marwin schrieb:
> Wie die meisten der "goldenen Regeln" ist auch diese einfach Unsinn.

In 99% der von Anfängern gebrachten Besipiele ist die schon zutreffend, 
aber zu jeder Regel gibt es zulässige Ausnahmen.

Frank schrieb:
> Kennt einer die Sysntax, bzw. wo überhaupt man beim IAR die 
Optimierungeinschalten kann?

Hm. DIESE Frage hätte ich jetzt nicht erwartet - das solltest du 
tatsächlich als allererstes klären, bevor du mit 
super-duper-pseudo-insider-C-Code-Verunstaltungs-bullshit-Optimierungstr 
icks  anfängst.

Oliver

von Frank (Gast)


Lesenswert?

Oliver schrieb:
> super-duper-pseudo-insider-C-Code-Verunstaltungs-bullshit-Optimierungstr icks

Das will ich ja erstmal garnicht ;-) Ich sag ja, letzte Option. Im 
Moment geht es mir ja mehr darum, meine Variante erstmal auf "normalem" 
Weg zu optimieren. Ich weiß es nicht unbedingt besser als mit der 
Variante, die ich euch grad gepostet hab. Ähnlich sehen meine anderen 
Module aus - es entstehen halt viele globale Variablen.

von Masl (Gast)


Lesenswert?

Deswegen der Zusatz - solang er weiß was er macht, darf er sowas gerne 
tun.

Es gibt halt Richtlinien, die haben sich im Laufe der Zeit als sinnvoll 
herausgestellt.
Ich glaube nicht, dass er sein Problem so lösen [i]muss[/i]. Da ist 
bestimmt noch woanders Spielraum.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Masl schrieb:
> Deswegen der Zusatz - solang er weiß was er macht, darf er sowas gerne
> tun.
>
> Es gibt halt Richtlinien, die haben sich im Laufe der Zeit als sinnvoll
> herausgestellt.
> Ich glaube nicht, dass er sein Problem so lösen [i]muss[/i]. Da ist
> bestimmt noch woanders Spielraum.

Da die Regel gilt, dass immer irgendwo ein Byte zu sparen ist, sollte 
jedes beliebige Problem in 2 Byte lösbar sein :-))))
Grüße, Kurt

von Karl H. (kbuchegg)


Lesenswert?

In deinem Code gilt zb
1
#define ADC_REPEAT_CYCLES 32
2
3
struct adc
4
{
5
  volatile uint8_t  repeat_counter;
6
  volatile uint32_t average_sum;
7
  volatile uint8_t  new_measurement;

ADC_REPEAT_CYCLES hast du dir durch
1
  adc_control.adc_result = ( adc_control.average_sum >> 5 );
auf 32 festgenagelt.
(Das ist zb für einen 'cleveren' Hack, der dein Softwaredesign zerstört. 
Das man durch 2-er Potenzen dividieren kann (bei unsigned Werten) indem 
man rechts schiebt, das ist etwas was C-Compiler seit rund 40 Jahren 
standardmässig machen. Auf Deutsch: Machs nicht selber! Du bringst dir 
nur selbst seltsame Abhängigkeiten in deinen Code rein, die dir 
irgendwann auf den Kopf fallen werden. Deine Compilerbauer sind doch 
keine Trottel, die haben dem Compiler das schon lange beigebracht. Wenn 
du dividieren willst, dann schreibs als Division hin. Ist es möglich die 
Division durch einen Shift zu ersetzten, dann lass das den Optimizer 
machen. Macht der das nicht, dann gibt es 2 Möglichkeiten
* dein Compiler ist Müll
* du hast die falschen Datentypen und in Wirklichkeit kann man die
  Division gar nicht allgmein durch Schieben ersetzen.
Beide Möglichkeiten lassen sich lösen. Aber versuch nicht dem Compiler 
Arbeit abzunehmen, indem du selber 'clever' Optimierungen machst, die 
der Compiler sowieso macht)


Weiters gilt:
Das Flag new_measurement brauchst du in Wirklichkeit gar nicht. Immer 
dann wenn new_measurement auf 1 steht, gilt: der repeat_count hat den 
Wert ADC_REPEAT_CYCLES.

Damit fällt der else Teil in der ISR raus, der Strukturmember fällt weg.

von Frank (Gast)


Lesenswert?

Um Divisionen durchzuführen habe ich es beispielsweise jetzt so:
1
uint32_t divide_number( uint16_t divider, uint32_t source_number )
2
{
3
  uint32_t divided_number;
4
  
5
  for( divided_number = 0; source_number >= divider; source_number -= divider )
6
  {
7
    divided_number++;
8
  }
9
  
10
  return divided_number;
11
}
Das nimmt nicht soviel Code weg, wie die direkte Division, ist aber echt 
relativ langsam, um so größer die Zahl wird, umso länger dauerts halt 
auch.

Das Teilen von 50000 / 10 dauert ca. 10ms - das ist schon echt 
megalangsam (Takt @ 8MHz)

von Dosmo (Gast)


Lesenswert?

Ein kommerzieller Compiler wie der IAR sollte eigentlich sehr gut 
selbständig auf Codegröße optimieren können, ohne daß man sich im C-Code 
unnötig verbiegen muß. Natürlich kann er aber keine Get/Set-Methoden 
durch globale Variablen ersetzen, das ginge zu weit.

Weiterhin solltest Du immer im Hinterkopf behalten, daß der Code 
verständlich und wartbar bleiben muß. Es hilft leider nichts, einen 100% 
optimalen Code zu haben, den niemand mehr nachvollziehen kann und schon 
bei der geringsten Änderung neugeschrieben werden muß.

Mein Tip: Laß erstmal den Compiler maximal optimieren, und schau, was 
übrig bleibt.

von Frank (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Machs nicht selber!

OK, haste wohl recht.

Karl Heinz Buchegger schrieb:
> Das Flag new_measurement brauchst du in Wirklichkeit gar nicht. Immer
> dann wenn new_measurement auf 1 steht, gilt: der repeat_count hat den
> Wert ADC_REPEAT_CYCLES.

Das ist z.B. wieder was, auf das ich nicht selbst gekommen bin, danke!

von Frank (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das man durch 2-er Potenzen dividieren kann (bei unsigned Werten) indem
> man rechts schiebt, das ist etwas was C-Compiler seit rund 40 Jahren
> standardmässig machen.

Also heißt das in dem Fall, dass ich ruhig /32 hinschreiben kann? Es 
wird vom Compiler durch >> 5 ersetzt. Wenn ich aber /33 schreibe, was 
keine 2er-Potenz ist, dann geht das gerödel los...

von Frank (Gast)


Lesenswert?

Frank schrieb:
> Also heißt das in dem Fall, dass ich ruhig /32 hinschreiben kann?

Also ich würde da jetzt auch ADC_REPEAT_CYCLES hinschreiben. Aber 
generell...

von Karl H. (kbuchegg)


Lesenswert?

Frank schrieb:

> Karl Heinz Buchegger schrieb:
>> Das Flag new_measurement brauchst du in Wirklichkeit gar nicht. Immer
>> dann wenn new_measurement auf 1 steht, gilt: der repeat_count hat den
>> Wert ADC_REPEAT_CYCLES.
>
> Das ist z.B. wieder was, auf das ich nicht selbst gekommen bin, danke!

Und genau das sind die Dinge, auf die du selber achten solltest, ehe du 
mit Trick-Optimierung anfängst.
Dort und mit besseren Algorithmen holt man sich Speicher und/oder Zeit.

von Marwin (Gast)


Lesenswert?

Simon K. schrieb:
> Die Methode hat nämlich einen riesen Haken: Du kannst jedes .c File nur
> ein mal inkludieren. Und damit zerstört man sich jegliches
> Programmierkonzept ("modulare Programmierung").

Das Gegenteil ist der Fall. Du kannst wunderbar modularisieren und 
brauchst dich nicht darum zu kuemmern, ob durch die Trennung in 
verschiedene Files suboptimaler Code entsteht. Nur beim Naming musst du 
aufpassen - aber das ist bei ordentlichem Code kaum ein Problem.

In der Realitaet sieht es doch so aus: Es wird auf der "goldenen Regel" 
rumgeritten und dann Code zusammen geschmissen, der besser in 
verschiedenen Files waere, mit globalen Variablen die Sichtbarkeit 
hergestellt um keine Accessoren verwenden zu muessen, etc, pp. Und das 
soll dann die modulare Programmierung "retten"?

von Simon K. (simon) Benutzerseite


Lesenswert?

Frank schrieb:
> Karl Heinz Buchegger schrieb:
>> Das man durch 2-er Potenzen dividieren kann (bei unsigned Werten) indem
>> man rechts schiebt, das ist etwas was C-Compiler seit rund 40 Jahren
>> standardmässig machen.
>
> Also heißt das in dem Fall, dass ich ruhig /32 hinschreiben kann? Es
> wird vom Compiler durch >> 5 ersetzt. Wenn ich aber /33 schreibe, was
> keine 2er-Potenz ist, dann geht das gerödel los...

Richtig. Dann machst du an das Define einen Kommentar, dass es für 
optimale Performance eine 2er Potenz sein muss.
Oder du erzeugst einen Compiler Error/Warning, wenn das keine 2er Potenz 
ist.

So wie es jetzt ist, ist es aber Mist. Änderst du die 32 in was Anderes, 
änderst aber nicht die Schiebeoperation, dann bekommst du _ohne 
jeglichen Hinweis_ komische Werte. Das ist einfach inkonsistentes 
Verhalten, dessen Ursache bei großen Programmen extrem schwer zu finden 
sein wird.

von Karl H. (kbuchegg)


Lesenswert?

Frank schrieb:
> Karl Heinz Buchegger schrieb:
>> Das man durch 2-er Potenzen dividieren kann (bei unsigned Werten) indem
>> man rechts schiebt, das ist etwas was C-Compiler seit rund 40 Jahren
>> standardmässig machen.
>
> Also heißt das in dem Fall, dass ich ruhig /32 hinschreiben kann? Es
> wird vom Compiler durch >> 5 ersetzt. Wenn ich aber /33 schreibe, was
> keine 2er-Potenz ist, dann geht das gerödel los...

Was ist dir lieber:
[ ] Ein Programm welches langsamer ist aber korrekte Ergebnisse bringt
[ ] Ein pfeilschnelles Programm, welches falsch rechnet?

Im übrigen sollst du nicht 32 hinschreiben sondern
1
 adc_control.adc_result = adc_control.average_sum / ADC_REPEAT_CYCLES;


Das löst man dann so
1
#define ADC_REPEAT_CYCLES 32     // muss eine 2-er Potenz sein

oder so
1
#define ADC_REPEAT_CYCLES (1<<5)

oder so
1
#define ADC_REPEAT_CYCLES_POWER   5
2
#define ADC_REPEAT_CYCLES (1<<ADC_REPEAT_CYCLES_POWER)

d.h. dadurch, dass ADC_REPEAT_CYCLES die geforderte Eigenschaft hat, so 
dass die restlichen Optimierungen greifen. Und das darf man dann auch 
ruhig mit einem Kommentar an dieser Stelle dokumentieren.

von Simon K. (simon) Benutzerseite


Lesenswert?

Marwin schrieb:
> Simon K. schrieb:
>> Die Methode hat nämlich einen riesen Haken: Du kannst jedes .c File nur
>> ein mal inkludieren. Und damit zerstört man sich jegliches
>> Programmierkonzept ("modulare Programmierung").
>
> Das Gegenteil ist der Fall. Du kannst wunderbar modularisieren und
> brauchst dich nicht darum zu kuemmern, ob durch die Trennung in
> verschiedene Files suboptimaler Code entsteht. Nur beim Naming musst du
> aufpassen - aber das ist bei ordentlichem Code kaum ein Problem.
Oh gott, bitte nicht! Ich habe "modulare Programmierung" schon erwähnt. 
Ein Modul hat eine Schnittstellendefinition (Header File) und eine 
Implementierung (Code File).
Habe ich jetzt zwei andere beliebige Module, die auf ein drittes Modul 
zugreifen möchten, dann inkludiere ich in beiden Fällen die Header-Datei 
und kann drauf zugreifen.

Bei "deiner" Methode, ginge das nicht. Wenn ich zwei mal das Code-File 
inkludiere, gibts entweder Linker-Fehler (duplicate definition) oder 
(vorausgesetzt du machst alles innerhalb des Moduls statisch) greifst 
auf zwei verschiedene Instanzen des Codes zu, der natürlich mehrfach im 
Flash liegt dann.
-> Ziemlich fatal in der Praxis.

> In der Realitaet sieht es doch so aus: Es wird auf der "goldenen Regel"
> rumgeritten und dann Code zusammen geschmissen, der besser in
> verschiedenen Files waere, mit globalen Variablen die Sichtbarkeit
> hergestellt um keine Accessoren verwenden zu muessen, etc, pp. Und das
> soll dann die modulare Programmierung "retten"?
Das stimmt hier einfach nicht. Ich kann dich verstehen, wenn du sagst, 
dass das Herumreiten auf goldenen Regeln oft nicht zum Ziel führt. Aber 
hier haben sich die entsprechenden Menschen tatsächlich was dabei 
gedacht.

von Simon K. (simon) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das löst man dann so
Oder so? (Nicht getestet)
1
#define ADC_REPEAT_CYCLES 32
2
#if ADC_REPEAT_CYCLES & (ADC_REPEAT_CYCLES - 1) != 0
3
#warning ADC_REPEAT_CYCLES is not a power of 2. Performance may decrease.
4
#endif

EDIT: Nein geht so nicht :-) Gedankenfehler. Modulo kann der 
Preprozessor vermutlich nicht?

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Frank schrieb:
> Das ist z.B. wieder was, auf das ich nicht selbst gekommen bin, danke!

Da hilft nur eines: Code gegenlesen lassen! Wir haben schon bei meinem 
ersten Arbeitgeber 1974 die Regel gehabt, Code gegenlesen zu lassen. Das 
hat zum einen das Knowhow gestreut, und zum anderen besseren Code 
ermöglicht. Leider sind solche Vorgehensweisen aus der Mode gekommen, 
auch wenn ein solches Verfahren gut zum agilen Programmieren passen 
würde.
Grüße, Kurt

von Oliver (Gast)


Lesenswert?

Dosmo schrieb:
> Ein kommerzieller Compiler wie der IAR sollte eigentlich sehr gut
> selbständig auf Codegröße optimieren können, ohne daß man sich im C-Code
> unnötig verbiegen muß. Natürlich kann er aber keine Get/Set-Methoden
> durch globale Variablen ersetzen, das ginge zu weit.

Aber selbstverständlich ersetzt jeder anständiger C-Compiler den Aufruf 
solcher setter/getter-Funktionen (und anderer auch) per inlining duch 
einen direkten Zugriff auf die Variable, wenn er das erkennen kann, und 
das dem Optimierungsziel (schneller oder kleiner) dienlich ist.

Oliver

von Frank (Gast)


Lesenswert?

So Leute, schonmal vielen Dank an euch!

Um nochmal auf meine Frage zurück zu kommen: Ist meine Variante mit 
diesen "globalen" Variablen denn sinnvoll? Oder anders...ist es OK, oder 
ganz schlechter Stil?

von Karl H. (kbuchegg)


Lesenswert?

Frank schrieb:

> Um nochmal auf meine Frage zurück zu kommen: Ist meine Variante mit
> diesen "globalen" Variablen denn sinnvoll? Oder anders...ist es OK, oder
> ganz schlechter Stil?

Für meine Begriffe ist das erst mal ok. Ich würd zumindest diesen 
gezeigten Teil so lassen. Wenn die Not groß ist, könnte man sich 
überlegen, ob man die adc_calc_result als 'static inline' Funktion mit 
ins Header File aufnimmt um eventuell durch den Wegfall des 
Funktionsaufrufs noch ein paar Bytes Code einzusparen (sofern die 
Funktion nur ein einziges Mal aufgerufen wird)

von Frank (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ich würd zumindest diesen
> gezeigten Teil so lassen.

Ich habe halt noch mehr davon, pwm_functions.h/c, ...,  welche ähnlich 
aufgebaut sind.

Ich danke euch auf jeden Fall sehr. Ich werde jetzt mal durch den Code 
gehen und gucken, ob ich noch mehr von solchen Variablen, die nur ein 
Flag beeinhalten, durch eh schon vorhandene Variablen ersetzen kann.

von Marwin (Gast)


Lesenswert?

Simon K. schrieb:
> Bei "deiner" Methode, ginge das nicht. Wenn ich zwei mal das Code-File
> inkludiere, gibts entweder Linker-Fehler (duplicate definition) oder
> (vorausgesetzt du machst alles innerhalb des Moduls statisch) greifst
> auf zwei verschiedene Instanzen des Codes zu, der natürlich mehrfach im
> Flash liegt dann.

Das sollst du auch gar nicht. Oben steht ganz klar, dass man (fuer 
diesen Fall hier) EIN C-File nimmt, was Alle anderen inkludiert. Du 
redest ein Problem herbei, wo keines ist.

von Marwin (Gast)


Lesenswert?

Oliver schrieb:
> Aber selbstverständlich ersetzt jeder anständiger C-Compiler den Aufruf
> solcher setter/getter-Funktionen (und anderer auch) per inlining duch
> einen direkten Zugriff auf die Variable, wenn er das erkennen kann, und
> das dem Optimierungsziel (schneller oder kleiner) dienlich ist.

Wir reden hier ueber Optimierung ueber Objektgrenzen hinweg, wo die 
Variable schlicht und einfach nicht mehr sichtbar ist. Da geht diese 
Optimierung nicht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.