Forum: Compiler & IDEs Modularisierung in C


von CompressorBoy (Gast)


Lesenswert?

Hallo,

ich habe mal gelesen, dass man in C möglichst modular programmieren 
soll.

Nun habe ich mittels eines Arduino Uno eine kleine 
Geschirrspül-Steuerung in C fertiggestellt, und zwar so, dass die 
Parameter für die einzelnen Spülgange (Vorspülen, Hauptspülen, 
Klarspülen etc.) in einem Array aus Structelementen gespeichert werden. 
Dies übernimmt meine Funktion Parameter_Lader, die im SetUp einmal 
aufgerufen wird und sich dabei der global vereinbarten 
Array-of-Struct-Variablen bedient. Meine Programmfunktion greift nun auf 
diesen Struct-Array zu und übergibt bestimmte Structelemente je nach 
Programmvariante (Normal oder Intensiv) den eigentlichen 
Steuerfunktionen (Wasserzulauf, Spülen, Abpumpen).
Klappt soweit alles gut.

Nur eben: modular programmiert ist das nicht.
Daher meine Frage: Wie kann ich einen Array-of-Structs von einer 
Funktion an die andere übergeben? Gibt es da einen Weg - oder gar 
mehrere?
Vielen Dank für die Antworten!

von Modularier (Gast)


Lesenswert?

Arrays werden mit einem Pointer übergeben. Für weitere Fragen am besten 
auch den Quellcode posten.

von J. F. (Firma: Père Lachaise) (rect)


Lesenswert?

Modularier schrieb:
> Arrays werden mit einem Pointer übergeben. Für weitere Fragen am besten
> auch den Quellcode posten.

Bitte zusätzlich die Größe des Arrays übergeben. So kann man in der 
Funktion selbst auf deinen Überlauf testen. Sonst tappt man dort nämlich 
im Dunkeln.

von Nop (Gast)


Lesenswert?

CompressorBoy schrieb:
> ich habe mal gelesen, dass man in C möglichst modular programmieren
> soll.

Jein. Bei größeren Projekten wird es unübersichtlich, wenn man zuviel 
mit globalen Variablen arbeitet, das stimmt. Aber:

1) ist das bei kleinen Projekten unpoblematisch.

2) ist es auch nur Kosmetik, wenn Du ohnehin nur eine solche Struktur 
hast und die dann überall mit Pointern weiterreichst. Es wird dann 
nämlich sowieso immer auf demselben globalen Objekt gearbeitet, also 
kein sonderlicher Unterschied.

Etwas anderes wäre es erst, wenn Deine eigentliche Waschfunktion (hier: 
einzel_spuel_vorgang) eben nicht den Pointer auf das "hier ist alles 
drin"-Gott-Objekt kriegt, also nicht das ganze array of structs, sondern 
nur die jeweils benötigten structs (mit nem Pointer darauf).

Beispiel, wie ich das meine. Dein struct-Array enthält in Komponente 0 
die Parameter fürs Vorspülen, in 1 die fürs Hauptspülen und in 2 die 
fürs Klarspülen. Diese Indices dann natürlich mit defines oder enums, 
nicht mit magic numbers.

Dann könnte das so aussehen, wobei Dein Parameterstruct ist (die 
Returnwerte können Fehlercodes sein):
1
enum {VORSPUELEN, HAUPTSPUELEN, KLARSPUELEN, MAXINDEX};
2
3
typedef struct t_param_set
4
{
5
  ...
6
} T_PARAM_SET;
7
8
...
9
10
T_PARAM_SET spuel_konfig[MAXINDEX-1];
11
12
...
13
14
int einzel_spuel_vorgang(T_PARAM_SET *param_set)
15
{
16
  ...
17
}
18
19
int komplett_spuelung(void)
20
{
21
  einzel_spuel_vorgang(&spuel_konfig[VORSPUELEN]);
22
  einzel_spuel_vorgang(&spuel_konfig[HAUPTPUELEN]);
23
  einzel_spuel_vorgang(&spuel_konfig[KLARSPUELEN]);
24
  return(fehlercode);
25
}

von Nop (Gast)


Lesenswert?

Nop schrieb:
> MAXINDEX-1

MAXINDEX natürlich.

von B. S. (bestucki)


Lesenswert?

Nop schrieb:
> 2) ist es auch nur Kosmetik, wenn Du ohnehin nur eine solche Struktur
> hast und die dann überall mit Pointern weiterreichst. Es wird dann
> nämlich sowieso immer auf demselben globalen Objekt gearbeitet, also
> kein sonderlicher Unterschied.

Doch es macht einen Unterschied. Einerseits in der Übersichtlichkeit und 
Lesbarkeit des Codes aber auch technisch, sobald ein Zeiger auf const 
übergeben wird.

Nop schrieb:
> Etwas anderes wäre es erst, wenn Deine eigentliche Waschfunktion (hier:
> einzel_spuel_vorgang) eben nicht den Pointer auf das "hier ist alles
> drin"-Gott-Objekt kriegt, also nicht das ganze array of structs, sondern
> nur die jeweils benötigten structs (mit nem Pointer darauf).
>
> Beispiel, wie ich das meine. Dein struct-Array enthält in Komponente 0
> die Parameter fürs Vorspülen, in 1 die fürs Hauptspülen und in 2 die
> fürs Klarspülen. Diese Indices dann natürlich mit defines oder enums,
> nicht mit magic numbers.

Wenn man das so machen will, kann man auch gleich einzelne Variablen 
erstellen und entsprechend benennen.


Ich habe den TO so verstanden, dass das Programm individuell 
zusammengestellt werden soll, also z.B. Vorspülen nicht zwingend 
vorkommen muss. Daher ist die Idee mit dem Array nicht falsch. Eine 
Alternative wäre, ein Array aus Zeigern (Liste) zu erstellen, die auf 
die Variablen zeigen.

von CompressorBoy (Gast)


Lesenswert?

Meine Güte, ist ja schon 'ne Menge los hier!
Vielen Dank für die Antworten, ich muss sie erst mal sichten.
Da jemand nach mehr Code-Info gefragt hatte - hier ist sie:

Der PARAMETER_LADER steht im SetUp (mit ein paar #defines zur besseren 
Lesbarkeit des Programms):
1
void PARAMETER_LADER(){
2
  
3
  par[laugenbehaelter_leeren] = {
4
    0 fuellhoehe, 
5
    0 spuelzeit, 
6
    heizung_aus};
7
  
8
  par[laugenbehaelter_spuelen_3] = {
9
    3 fuellhoehe, 
10
    0 spuelzeit, 
11
    heizung_aus};
12
  
13
  par[vorspuelen_kalt] = {
14
    2 fuellhoehe, 
15
    20 spuelzeit, 
16
    heizung_aus};
17
18
  .
19
  .
20
  .
21
22
par[klarspuelen_warm] = {
23
    2 fuellhoehe, 
24
    20 spuelzeit, 
25
    heizung_an};}


Typdefinintion und Festlegung einer Arrayvariablen dieses Typs sind 
global:
1
typedef struct {
2
  uint wasserstand; 
3
  ulong spueldauer; 
4
  bool heizung;} parameter;
5
6
  parameter par[20];


Das eigentliche Spülprogramm steht in der Schleife:
1
void NORMALPROGRAMM(){
2
3
  uint prog[] = {
4
    laugenbehaelter_leeren,
5
    hauptspuelen_mittel,
6
    klarspuelen_kalt,
7
    laugenbehaelter_spuelen_2,
8
    klarspuelen_warm,
9
    programm_ende};
10
11
    uint count;
12
  
13
  uint startverzoegerung = 3 sec;
14
  delay(startverzoegerung);
15
16
  digitalWrite(Hauptstromversorgung, AN);
17
  
18
  while (prog[count] < programm_ende) {
19
    WASSERZULAUF(par[prog[count]]);
20
    count++;}
21
  
22
  digitalWrite (Hauptstromversorgung, AUS);
23
  while(1);}


während die miteinander verketteten Spülfunktionen sind:
1
void WASSERZULAUF(parameter par){
2
  uint beruhigungszeit = 6 sec;
3
  uint abfragezeit = 100 msec;
4
  uint pufferzeit = 300 msec;
5
  uint einlass;
6
 
7
  if (par.wasserstand) 
8
    goto EndWasserzulauf;
9
  while (einlass < par.wasserstand){
10
    digitalWrite (Magnetventil, AN);
11
    while (digitalRead(Zulaufschalter))
12
      delay (abfragezeit);
13
    digitalWrite (Magnetventil, AUS);
14
    delay (pufferzeit);
15
    while (!digitalRead(Zulaufschalter))
16
      delay (abfragezeit);
17
    einlass++;}
18
  delay (beruhigungszeit);
19
  
20
  EndWasserzulauf: SPUELEN (par);
21
  return;}
22
  
23
24
void SPUELEN(parameter par){
25
  uint heizelementbenetzung = 10 sec;
26
  uint heizelementabkuehlung = 10 sec;
27
  uint abtropfzeit = 3 sec;
28
  
29
  if (!par.spueldauer) 
30
    goto EndSpuelen;
31
  digitalWrite (Umwaelzpumpe, AN);
32
  
33
  if (par.heizung){
34
    delay (heizelementbenetzung); 
35
    digitalWrite (Heizung, AN);}
36
  delay (par.spueldauer);
37
  if (par.heizung){
38
    digitalWrite (Heizung, AUS); 
39
    delay (heizelementabkuehlung);}
40
  digitalWrite (Umwaelzpumpe, AUS); 
41
  delay (abtropfzeit);
42
  
43
  EndSpuelen: ABPUMPEN (par);
44
  return;}
45
46
47
void ABPUMPEN(parameter par){
48
  
49
  uint abpumpdauer;
50
  uint beruhigungszeit = 1 sec;
51
  
52
  if (!par.wasserstand)
53
    abpumpdauer = 6 sec; 
54
  else abpumpdauer = par.wasserstand * 6 sec;
55
  
56
  digitalWrite (Ablaufpumpe, AN); 
57
  delay (abpumpdauer);
58
  digitalWrite (Ablaufpumpe, AUS); 
59
  delay (beruhigungszeit);
60
  
61
  EndAbpumpen: return;}

von B. S. (bestucki)


Lesenswert?

CompressorBoy schrieb:
> parameter par[20];

Woher kommt die 20? Magic Number?


CompressorBoy schrieb:
> uint count;

Nicht initialisierte Variable. Oder setzt das Arduino-Framework die 
Variable auf null?


CompressorBoy schrieb:
> if (par.wasserstand)
>     goto EndWasserzulauf;
>   ...
>
>   EndWasserzulauf: SPUELEN (par);

Warum nicht
1
if(!par.wasserstand){
2
 ...
3
}
4
5
SPUELEN(par);


Die ganze Sache ist noch etwas unübersichtlich. Du benutzt für drei 
Verschiedene Dinge den Gleichen Datentyp (parameter). Auch die Funktion 
WASSERZULAUF tut nicht nur das, was sie verspricht, nämlich die Maschine 
mit Wasser füllen. Sie ruft auch noch SPUELEN auf, die wiederum ABPUMPEN 
aufruft. Besser wäre folgende Struktur:
1
void WaschprogrammDurchfuehren(...){
2
  WasserFuellen(...);
3
  Spuelen(...);
4
  Abpumpen(...);
5
}


Noch was: Identifier in Grossbuchstaben sind in C normalerweise für 
defines reserviert. Dies ist keine Pflicht, wird aber von der grossen 
Mehrheit so gemacht.

von Peter D. (peda)


Lesenswert?

CompressorBoy schrieb:
> typedef struct {
>   uint wasserstand;
>   ulong spueldauer;
>   bool heizung;} parameter;

Sicher, daß Du die Spüldauer auf 1ms genau bis 49d angeben mußt?
Und den Wasserstand auf 1ml genau bis 65l.
Bei der Heizung würde ich dagegen wählbar machen, ob 50, 55 oder 65°C.

3 * uint8_t sollten reichen:
Wasser: 0,1l .. 25l
Zeit: 1min .. 255min
Temperatur: aus, 50, 55, 60°C

von W.S. (Gast)


Lesenswert?

CompressorBoy schrieb:
> ich habe mal gelesen, dass man in C möglichst modular programmieren
> soll.

Das Beispiel mit dem struct ist wirklich nicht das, was es sein sollte.

Also: modular programmieren besteht im Wesentlichen daraus, daß man 
nicht aalles wahllos in eine Quelle hineinwirft. In jeder Firmware gibt 
es Programmteile, die sich um Dinge unterschiedlichen Niveaus kümmern. 
Das nimmt man auseinander und verpackt es in separate Quellen.

Mal ein Beispiel:
- Startupcode
- Konfigurationsmodul (Pinbelegungen, Takt usw.)
- Low Level Treiber für "Hände und Füße", also z.B. einer für den Motor, 
ein anderer für das Spülwasser-Ventil, einer für die Regelung der 
Waschtemperatur, einer für die Bedienung der Anzeige, einer für das 
Abfragen und Entprellen der Knöpfe und so weiter.
- ein Modul für das Organisieren des Waschvorgangs, also Abläufe 
organisieren
- ein Modul für Kommandogabe und Darstellung, also was man wie an 
welcher Stelle im Programmablauf machen kann und Organisation dessen, 
was man dabei auf dem Display zu sehen kriegt
- ein Modul für die Systemzeit und Zeitüberwachungen
- main mit der Grundschleife

So ungefähr geht sowas. Das Prinzip dabei ist, daß eben nur diejenigen 
Module sich mit den Einzelheiten der HW abgeben, die dafür auch gedacht 
sind. Der Modul für die Abläufe sollte z.B. überhaupt keine HW direkt 
anfassen, sondern lediglich "Kommandos" erteilen, wie z.B. Motor_Ein() 
oder Heizung_auf(45.5); (°Celsius) - und wie der Motortreiber den Motor 
einschaltet, ist sein Bier und interessiert den Rest der ganzen Firmware 
überhaupt nicht.

W.S.

von Christopher C. (trihexagon)


Lesenswert?

Nop schrieb:
> CompressorBoy schrieb:
>> ich habe mal gelesen, dass man in C möglichst modular programmieren
>> soll.
>
> Jein. Bei größeren Projekten wird es unübersichtlich, wenn man zuviel
> mit globalen Variablen arbeitet, das stimmt. Aber:

Solang die Variablen nur im Modul "global" sind (static), ist das völlig 
unproblematisch. Nur globale Variablen, die übers ganze Projekt 
manipulierbar sind, sind böse.

led.c
1
static bool toggleMode = false;
2
static uint32_t togglePeriodMs = 1000;
3
//...
4
5
void led_init();
6
void led_enableToggleMode(uint32_t periodMs);
7
//...

toggleMode und togglePeriodMs sind nur in der led.c, also im Modul, 
erreichbar. Schön gekapselt. So spart man sich auch irgendwelche Zieger 
auf eine Struktur mit den Membervariablen des Moduls. Gleiches gilt für 
static functions.

: Bearbeitet durch User
von CompressorBoy (Gast)


Lesenswert?

Mein Grundgedanke bei der Programmerstellung war, es bezüglich künftiger 
Änderungen flexibel zu gestalten in der Form, dass weitere Spülprogramme 
aus einzeln parametrierten Spülmodulen zusammengestellt werden können, 
um eben auch künftigen Anforderungen gerecht werden zu können.

Nur dachte ich eben, dass es vielleicht eleganter ist, wenn der 
Parameter_Lader seine Struct-Elemente nicht global herum flottieren 
lässt, sondern sie als return-Wert direkt derjenigen Funktion übergibt, 
welche sie braucht.

von Eric B. (beric)


Lesenswert?

CompressorBoy schrieb:
> Mein Grundgedanke bei der Programmerstellung war, es bezüglich künftiger
> Änderungen flexibel zu gestalten in der Form, dass weitere Spülprogramme
> aus einzeln parametrierten Spülmodulen zusammengestellt werden können,
> um eben auch künftigen Anforderungen gerecht werden zu können.
>
> Nur dachte ich eben, dass es vielleicht eleganter ist, wenn der
> Parameter_Lader seine Struct-Elemente nicht global herum flottieren
> lässt, sondern sie als return-Wert direkt derjenigen Funktion übergibt,
> welche sie braucht.

Warum brauchst du überhaupt diese Parameter_lader? Die ganze 
parameter-Struktur kann auch statisch angelegt werden:
1
typedef struct {
2
  uint8_t water_level;
3
  uint8_t duration;
4
  uint8_t temperature;
5
} ProgramType;
6
7
static ProgramType Programs[] = {
8
  { 0,  0,  0 }, /* Program 0: empty out */
9
  { 2, 20, 65 }, /* Program 1: normal dish washing */
10
  ...
11
};
12
13
#define PROG_EMPTY 0
14
#define PROG_NORMAL 1
15
...
16
17
void run_program(uint8_t program)
18
{
19
  setTemperature(Programs[program].temperature);
20
  ...
21
}

: Bearbeitet durch User
von CompressorBoy (Gast)


Lesenswert?

@Eric B:

gute Idee!
Hat static die gleiche Wirkung wie const?
Und kann man struct-Variablen const-ant machen?

von S. R. (svenska)


Lesenswert?

> Hat static die gleiche Wirkung wie const?

Nein, denn sonst gäbe es keine Unterschiedlichen Begriffe dafür.

> Und kann man struct-Variablen const-ant machen?

Ja.

von Nop (Gast)


Lesenswert?

CompressorBoy schrieb:
> Und kann man struct-Variablen const-ant machen?

Auf die Frage "was heißt const" zu Antworten "das sind Konstanten", ist 
übrigens ein hervorragender Weg, in einem Bewerbungsgespräch umgehend 
durchzufallen.

von CompressorBoy (Gast)


Lesenswert?

Wieso?
Sind sie doch auch in dem Sinne, dass sie festgesetzt sind und während 
des Programmlaufs nicht mehr geändert werden können.

von A. S. (Gast)


Lesenswert?

CompressorBoy schrieb:
> Sind sie doch auch in dem Sinne, dass sie festgesetzt sind und während
> des Programmlaufs nicht mehr geändert werden können.

Durchgefallen ;-)
1
extern const int x;
bedeutet ausdrücklich nicht, dass x konstant ist. Sondern nur, dass x 
in C kein Wert direkt zugewiesen werden darf. Aber vielleicht mit 
EEPROM-Write oder mit einem Cast oder mit memcpy.... .Natürlich musst Du 
das auch mit Deinem Linker klären.

Bei Read-Only-Registern ist sogar
1
const volatile int x;
 üblich.

von Heiner (Gast)


Lesenswert?

Peter D. schrieb:
> Sicher, daß Du die Spüldauer auf 1ms genau bis 49d angeben mußt?
> Und den Wasserstand auf 1ml genau bis 65l.
> Bei der Heizung würde ich dagegen wählbar machen, ob 50, 55 oder 65°C.
>
> 3 * uint8_t sollten reichen:
> Wasser: 0,1l .. 25l
> Zeit: 1min .. 255min
> Temperatur: aus, 50, 55, 60°C

Der Herr Sonnenschein mal wieder in seiner typischen arroganten Art.

Lg Heiner

von CompressorBoy (Gast)


Lesenswert?

Achim S. schrieb:
> Durchgefallen ;-)

Au weia :-) ...
Aber immerhin habe ich was dazugelernt.
Na ja, ich bin in C ja noch ein Newbie, und was Kenntnissen noch nicht 
da ist, kann ja noch kommen.
Klar ist: da C eine hardwarenahe Sprache ist, die auf dieser Ebene viele 
Dinge ansprechen kann, muss man die (Mikrocontroller-)Hardware gut genug 
kennen.
Ich werde daran arbeiten...

von Peter D. (peda)


Lesenswert?

Solche Ablaufsteuerungen würde ich mit einer Statemaschine (switch/case) 
aufbauen, quasi analog einem Schrittschaltwerk.
Ist ein Parameter 0, wird der entsprechde Schritt übersprungen.
D.h. man hat eine Parameterliste, die das switch/case einfach der Reihe 
nach durchackert (den Index hochzählt).

von Nop (Gast)


Lesenswert?

Peter D. schrieb:

> D.h. man hat eine Parameterliste, die das switch/case einfach der Reihe
> nach durchackert (den Index hochzählt).

Wenn man das in eine while-Schleife verpackt, kann man sogar effektiv 
mit gotos in der Statemachine herumspringen, ohne jemals die 
Zeichenfolge "goto" tippen zu müssen. Ein Hoch auf die strukturierte 
Programmierung. (;

von Eric B. (beric)


Lesenswert?

S. R. schrieb:
>> Und kann man struct-Variablen const-ant machen?
>
> Ja.

Dann sind es aber keine Variablen mehr ;-)

von S. R. (svenska)


Lesenswert?

"extern const volatile struct io_pin" ?
Sowas ähnliches habe ich letztens gebastelt, da lokale Registeradressen 
nur über externe Speicherzugriffe erreichbar waren, deren Adressraum zur 
Compilezeit nicht feststelt.

von Nop (Gast)


Lesenswert?

Eric B. schrieb:
> Dann sind es aber keine Variablen mehr ;-)

Direkt nach dem Durchfallen des Vorgängers mit demselben Ansatz nochmal 
durchzufallen, ist wohl die hohe Kunst des Durchfallens. ^^

Denkanstoß: Ein struct, das auf IO-Register mappt, welche readonly sind, 
sich aber durchaus ändern können. Statusregister beispielsweise, oder 
AD-Wandler-Datenregister.

von Eric B. (beric)


Lesenswert?

Nop schrieb:
> Eric B. schrieb:
>> Dann sind es aber keine Variablen mehr ;-)
>
> Direkt nach dem Durchfallen des Vorgängers mit demselben Ansatz nochmal
> durchzufallen, ist wohl die hohe Kunst des Durchfallens. ^^

Haste Recht. Lektion für heute: zuerst den Draht bis zum Ende 
durchlesen, dann antworten :-)

von CompressorBoy (Gast)


Lesenswert?

Wenn ich hier "Statemaschine" lese, wird mir klar, wieviel ich noch 
lernen muss.
Gibt es (relativ) leicht verständliche Bücher, die diese und ähnliche 
Programmiertechniken in Bezug auf Mikrocontroller darlegen?

von A. S. (Gast)


Lesenswert?

Nop schrieb:
> Wenn man das in eine while-Schleife verpackt, kann man sogar effektiv
> mit gotos in der Statemachine herumspringen, ohne jemals die
> Zeichenfolge "goto" tippen zu müssen. Ein Hoch auf die strukturierte
> Programmierung. (;

Unsere Cash-Cow ist ein Applikations-Code mit etwa 500k LOC. Und 
irgendwo 1(!) goto (sprintf-Clone glaube ich). Im Rahmen der 
Zertifizierung habe ich hochnotpeinlich eingeräumt, dieses goto bewusst 
belassen zu haben und mich geweigert, es umzuschreiben.

Was war das für ein Triumpf des Firmwerkers, der wenige Tage zuvor in 
seinen etwa 100k LOC alle Gotos (mehrere 100!!!) durch while / case 
ersetzt hat. Er war sauber! Und mit den auskommentierten Originalzeilen 
war es sogar lesbar (zumindest so viel oder wenig wie zuvor).

von Achim.S (Gast)


Lesenswert?

CompressorBoy schrieb:
> Wenn ich hier "Statemaschine" lese

Statusmaschine heisst eigentlich nur, ich bin in diesem State (z.B. 
aufheizen oder auf Taste warten) dann passiert das (Temperatur erreicht, 
Timeout oder Taste gedrückt) und dann wechsle ich in den State ...

Es gibt verschiedenste Ausführungen und Paradigmen, Darstellungsweisen 
und Notationen.

Unabhängig davon gibt es aber zwei grundsätzlich Arten der 
Implementierung

a) Eventgesteuert

b) SPS-Loop


Bei a) hast Du je Statusmaschine eine Task mit Endlosschleife, die auf 
Events wartet (auch Timeout ist ein Event) und dann irgendwas tun.

Bei b) hast Du je Statusmaschine eine Funktion, die zyklisch ohne 
blockierende Aktionen nacheinander durchlaufen werden.

Die Unterschiede und Konsequenzen sind so gravierend, dass Du mit beiden 
Konzepten Erfahrungen sammeln solltest, und intensiv mit b ;-)

von W.S. (Gast)


Lesenswert?

Achim S. schrieb:
> Durchgefallen ;-)
> extern const int x; bedeutet ausdrücklich nicht, dass x konstant ist.

Vorsicht, mein Lieber. Wir sind hier nicht bei der PC-Programmierung, 
sondern bei Mikrocontrollern. Und da kann es dir durchaus passieren, daß 
du bei solchen Variablen schlichtweg auf Stein beißt, weil sowas auch 
mal im Flash stehen kann.

Noch deftiger wird das Ganze, wenn du ne Harvard-Architektur hast, wo du 
für etwaige Zugriffe auf den Flash (=Befehlsspeicher) nen völlig anderen 
Maschinenbefehl (oder ne Hardware-Einrichtung wie bei den PIC's) 
brauchst als bei RAM-Zugriffen.

Ich halte vom inflationären Gebrauch von const nichts, ein ähnliches 
gilt für sowas wie static. Schlimme unsystematische 
Programmiergewohnheiten kann man dadurch auch nicht besser machen.

W.S.

von A. S. (Gast)


Lesenswert?

W.S. schrieb:
> Vorsicht ....weil sowas auch mal im Flash stehen kann.

Achim S. schrieb:
> Natürlich musst Du das auch mit Deinem Linker klären.

W.S. schrieb:
> für etwaige Zugriffe auf den Flash (=Befehlsspeicher) nen völlig anderen
> Maschinenbefehl (oder ne Hardware-Einrichtung wie bei den PIC's)
> brauchst als bei RAM-Zugriffen.

Achim S. schrieb:
> Sondern nur, dass x in C kein Wert direkt zugewiesen
> werden darf. Aber vielleicht mit EEPROM-Write

Wenn der Compiler das Lesen nicht hinkriegt, kann er keine Variable 
dahinlegen, auch keine const.

von Nop (Gast)


Lesenswert?

Achim S. schrieb:
> Durchgefallen ;-)
> extern const int x; bedeutet ausdrücklich nicht, dass x konstant ist.

Vorsicht in der Kurve. Wenn in dem C-File, wo x wirklich deklariert ist, 
x nicht als const int, sondern als int deklariert ist, dann sind das 
inkompatible Typen, und somit man ist im undefined behaviour.

Quelle mit Verweis auf die relevanten Parts des C-Standards:

http://stackoverflow.com/questions/27724453/declaring-a-global-variable-extern-const-int-in-header-but-only-int-in-sourc

extern const ist kein Weg, wie man im Falle globaler Variablen einem 
anderen Modul die Variable als read-only zur Verfügung stellen kann. 
Will man das machen, braucht man eine getter-Funktion.

von Nop (Gast)


Lesenswert?

W.S. schrieb:
> Ich halte vom inflationären Gebrauch von const nichts, ein ähnliches
> gilt für sowas wie static.

Ich setze const immer ein, wenn ich Funktionen habe, die einen Pointer 
akzeptieren, aber die Daten nur lesen. Dann sieht man nämlich direkt im 
Prototypen schon, daß die Funktion keine Seiteneffekte auf die 
referenzierten Daten hat.

Static setze ich auch exzessiv ein, wenn ich klarmachen will, daß eine 
Funktion nur im Filescope existiert, weil das dem Compiler ein 
aggressiveres Inlining ermöglicht. Und bei globalen Variablen, um 
klarzumachen, daß die nur in dem File relevant sind.

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.