Forum: Mikrocontroller und Digitale Elektronik static const PROGMEM in eigenes File auslagern


von L. N. (derneumann)


Lesenswert?

Ahoi,

habe folgenden Thread gelesen und habe eigentlich die gleiche 
Anforderung:
Beitrag "Wie PROGMEM Konstante in .h Datei auslagern?"

>.c :
>
>  uint8_t Werte[] PROGMEM = {1,2,3,4,5};
>
>.h :
>
>  extern uint8_t Werte[] PROGMEM;

Bringt mir nichts, weil ich genauso den INHALT der Variable in ein 
eigenes File auslagern will. Hiermit hätte ich die lange Wurst wieder in 
der main.cpp. Habe auch schon an anderer Stelle ergooglet, dass das "the 
way to go" ist.

---

Das hier scheint ja nun zu funktionieren auch wenn es nicht ganz sauber 
zu sein scheint, aber gibt es auch einen Weg der nicht nur 
"funktioniert" sondern auch Best Practice oder Regelkonform ist?

main.c:
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
#include "progmemconst.h"
4
5
int main()
6
{
7
8
  unsigned char counter;
9
10
  while(1)
11
  {
12
    for (counter = 0; counter < 6; counter++)
13
    {
14
      PORTA = pgm_read_byte(&Werte[counter]);
15
    }
16
17
  }
18
19
20
}

progmemconst.h:
1
#ifndef _PROGMEMCONST_H_
2
#define _PROGMEMCONST_H_
3
4
#include <avr/pgmspace.h>
5
6
static const uint8_t Werte[] PROGMEM = {1,2,3,4,5};
7
8
#endif

Danke!

von Stefan F. (Gast)


Lesenswert?

Eine gängige Vorgehensweise ist, ein Hilfsprogramm zu verwenden, dass 
aus den Files einen Quelltext mit Byte-Arrays erzeugt.

Dieser Thread könnte für Doch interessant 
sein:https://stackoverflow.com/questions/4864866/c-c-with-gcc-statically-add-resource-files-to-executable-library

von Oliver S. (oliverso)


Lesenswert?

L. N. schrieb:
> Bringt mir nichts, weil ich genauso den INHALT der Variable in ein
> eigenes File auslagern will.

Warum? Was willst du damit erreichen?

Oliver

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

L. N. schrieb:
> Bringt mir nichts, weil ich genauso den INHALT der Variable in ein
> eigenes File auslagern will. Hiermit hätte ich die lange Wurst wieder in
> der main.cpp.

Nö. Der Inhalt der Variablen kann selbstverständlich in eine eigene 
Datei gepackt werden, sie darf nur nicht static sein.

main.c (oder .cpp)
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
#include "progmemconst.h"
4
5
6
.. etc.

progmemconst.h:
1
extern const uint8_t Werte[] PROGMEM;

progmemconst.c (oder .cpp)
1
#include <avr/pgmspace.h>
2
#include "progmemconst.h"
3
4
const uint8_t Werte[] PROGMEM = {1,2,3,4,5};


Ziemlich genau das gleiche habe ich vor sieben Jahren schon geschrieben.

von Nop (Gast)


Lesenswert?

Tip: man kann mit #include auch .c-Dateien inkludieren.

von holger (Gast)


Lesenswert?

>Tip: man kann mit #include auch .c-Dateien inkludieren.

Wer das macht frisst auch kleine Kinder;)

von Hmmm (Gast)


Lesenswert?

Nop schrieb:
> Tip: man kann mit #include auch .c-Dateien inkludieren.

Warum eklig, wenn es auch sauber geht?

von Nop (Gast)


Lesenswert?

Hmmm schrieb:
> Nop schrieb:
>> Tip: man kann mit #include auch .c-Dateien inkludieren.
>
> Warum eklig, wenn es auch sauber geht?

Weil dann auch "static" geht.

von L. N. (derneumann)


Lesenswert?

Danke an alle!

@static: wenn ich jetzt noch wüsste, warum ich das damals static gemacht 
hab...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nop schrieb:
> Weil dann auch "static" geht.

Aber es ist Blödsinn.

von L. N. (derneumann)


Lesenswert?

Rufus Τ. F. schrieb:
> Nop schrieb:
>> Weil dann auch "static" geht.
>
> Aber es ist Blödsinn.

was macht man wenn es static sein muss? warum auch immer, hab wie gesagt 
keine ahnung mehr warum ich das static gemacht hab.

muss mir 1) erst wieder anschauen wofür static ist und 2) was ich da 
gemacht hab

mache code cleanup von einem 6 monate alten projekt und hab genau so 
lang kein C mehr programmiert (und bin sowieso kein profi).

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

L. N. schrieb:
> was macht man wenn es static sein muss?

Unter welchen Bedingungen kann das der Fall sein, abgesehen vom 
Einhalten von Prinzipien?

Sofern irgendwo eine andere globale Variable gleichen Namens existiert, 
muss man halt einen anderen Namen wählen.

Aber in der Verwendung, insbesondere in einem µC, fällt mir wirklich 
kein Grund ein, warum eine Variable static sein muss.

Das static definiert schließlich nur die Sichtbarkeit des Symbolnamen 
auf Linkerebene, es geht hier schließlich nicht um den Unterschied zu 
automatischen (d.h. auf dem Stack angelegter) Variablen.

von L. N. (derneumann)


Lesenswert?

Rufus Τ. F. schrieb:
> L. N. schrieb:
>> was macht man wenn es static sein muss?
>
> Unter welchen Bedingungen kann das der Fall sein, abgesehen vom
> Einhalten von Prinzipien?
>
> Sofern irgendwo eine andere globale Variable gleichen Namens existiert,
> muss man halt einen anderen Namen wählen.
>
> Aber in der Verwendung, insbesondere in einem µC, fällt mir wirklich
> kein Grund ein, warum eine Variable static sein muss.
>
> Das static definiert schließlich nur die Sichtbarkeit des Symbolnamen
> auf Linkerebene, es geht hier schließlich nicht um den Unterschied zu
> automatischen (d.h. auf dem Stack angelegter) Variablen.


STACK ist das stichwort. die daten sollen lediglich im flash liegen, da 
sehr groß. der stack hat 4kb beim esp8266 (um das es hier geht) und den 
würde ich sprengen.

von L. N. (derneumann)


Lesenswert?

Stefan U. schrieb:
> Eine gängige Vorgehensweise ist, ein Hilfsprogramm zu verwenden, dass
> aus den Files einen Quelltext mit Byte-Arrays erzeugt.
>
> Dieser Thread könnte für Doch interessant
> 
sein:https://stackoverflow.com/questions/4864866/c-c-with-gcc-statically-add-resource-files-to-executable-library

Puuh, interessanter (schlauer) Ansatz, steige aber nicht ganz durch wie 
ich das mit PlatformIO oder der Arduino IDE lösen könnte (vermutlich gar 
nicht). Da steckt mir dann zu viel Voodoo drin :D

Oliver S. schrieb:
> Warum? Was willst du damit erreichen?
>
> Oliver

Mehr Übersichtlichkeit im Code.

Rufus Τ. F. schrieb:
> L. N. schrieb:
>> Bringt mir nichts, weil ich genauso den INHALT der Variable in ein
>> eigenes File auslagern will. Hiermit hätte ich die lange Wurst wieder in
>> der main.cpp.
>
> Nö. Der Inhalt der Variablen kann selbstverständlich in eine eigene
> Datei gepackt werden, sie darf nur nicht static sein.
>
> main.c (oder .cpp)
> #include <avr/io.h>
> #include <avr/pgmspace.h>
> #include "progmemconst.h"
>
> .. etc.
>
> progmemconst.h:
> extern const uint8_t Werte[] PROGMEM;
>
> progmemconst.c (oder .cpp)
> #include <avr/pgmspace.h>
> #include "progmemconst.h"
>
> const uint8_t Werte[] PROGMEM = {1,2,3,4,5};
>
> Ziemlich genau das gleiche habe ich vor sieben Jahren schon geschrieben.

Stimmt, hab deinen alten Post falsch verstanden.

Nop schrieb:
> Tip: man kann mit #include auch .c-Dateien inkludieren.

uuh, offensichtlich dirty talk :D des arduino frickel-pfuschers (ich) 
freund, sofern kein sofort offensichtlicher fehler auftritt :D wobei ich 
eine saubere lösung auch bevorzugen würde, falls möglich.

Rufus Τ. F. schrieb:
> Das static definiert schließlich nur die Sichtbarkeit des Symbolnamen
> auf Linkerebene, es geht hier schließlich nicht um den Unterschied zu
> automatischen (d.h. auf dem Stack angelegter) Variablen.

Wie gesagt, Stack wird wohl das Stichwort sein. Ich nutze den Arduino 
Core für das ESP8266 und dort ist der Stack auf 4k beschränkt. Habe ihn 
zwar schon auf 8k angehoben weil ich die Firmware sonst nicht 
reingepresst bekommen habe, wenn man es übertreibt gibts aber 
Stabilitätsprobleme und die 8k Anhebung war schon ein dirty Hack. 
Mittlerweile hab ich zwar viel umgeschrieben und könnte vermutlich 
wieder mit 4k auskommen, wenn ich aber nun die Daten die ich in der 
static const char bla[] PROGMEM drin hab wieder nicht static mache (und 
damit in den stack lade), knallt es wieder.

kreative ansätze, außer .c zu includen?

von Oliver S. (oliverso)


Lesenswert?

.h includen, wie du es oben schon gemacht hast. Solange du die .h-Datei 
nirgendwo anders includest, ist damit alles in Ordnung.

Oliver

von L. N. (derneumann)


Lesenswert?

Oliver S. schrieb:
> .h includen, wie du es oben schon gemacht hast. Solange du die .h-Datei
> nirgendwo anders includest, ist damit alles in Ordnung.
>
> Oliver

Stimmt, das hatte ich schon wieder vergessen, danke!
Noch immer nicht Regel konform scheinbar, aber noch immer besser als 
Kinder zu fressen. ;-)

von Carl D. (jcw2)


Lesenswert?

L. N. schrieb:
> Oliver S. schrieb:
>> .h includen, wie du es oben schon gemacht hast. Solange du die .h-Datei
>> nirgendwo anders includest, ist damit alles in Ordnung.
>>
>> Oliver
>
> Stimmt, das hatte ich schon wieder vergessen, danke!
> Noch immer nicht Regel konform scheinbar, aber noch immer besser als
> Kinder zu fressen. ;-)

Wenn ohne static, dann darf es nur ein c-File geben, das der Compiler 
übersetzt, sonst meldet der Linker "duplicate symbol".
(typische makefiles mit "*.c"-Regeln beißen sich da mit 
".c"-Include-Files)

Mit static gibt es die Daten pro übersetztem c-File genau ein mal und 
zwar ohne externes Symbol, d.h. der Linker meckert nicht, sondern legt 
brav mehrere Kopien ins Flash.

Es geht also weniger um "das gehört sich nicht",
sondern eher um "es gibt nur einen sinnvollen Weg":
Extern Variable mit eigener Übersetzungseinheit (".c"-File).
Der tut auch nicht weh.

von Nop (Gast)


Lesenswert?

Rufus Τ. F. schrieb:

> Unter welchen Bedingungen kann das der Fall sein, abgesehen vom
> Einhalten von Prinzipien?

Compiler-Optimierungen. Mit static sieht der Compiler die komplette 
Benutzung beim Übersetzen der Übersetzungseinheit.

Mal ganz abgesehen davon ist es auch nicht "dreckig", wenn man Dateien 
inkludiert, die nicht auf .h enden. Daß meistens .h-Files inkludiert 
werden, ist natürlich richtig, aber man kann jede Datei inkludieren.

Die Schach-Engine Crafty ist wohl vielen ein Begriff, und die wird 
gebaut, indem in crafty.c alle c-Files mit #include reingezogen werden. 
Im Makefile ist crafty.o das (!) Objektfile. Hintergrund ist bessere 
Performance.

Wer trotzdem Panik bekommt, kann die Datei ja auch auf .dat enden 
lassen.


L. N. schrieb:

> STACK ist das stichwort.

Nope, denn file-static und global macht keinen Unterschied. static ist 
für Stack nur relevant, wenn es um funktionslokale Variablen geht, nicht 
um globale.

von Nop (Gast)


Lesenswert?

L. N. schrieb:
> kreative ansätze, außer .c zu includen?

Die Datei in .dat umbenennen. Oder in .h. ^^

von Carl D. (jcw2)


Lesenswert?

Nop schrieb:
> Compiler-Optimierungen. Mit static sieht der Compiler die komplette
> Benutzung beim Übersetzen der Übersetzungseinheit.
Es gibt auch Compiler, die sowas von Haus aus können.
Das Code-Beispiel inkludiert <avr.io>, also wohl GCC und damit auch LTO. 
(GCC-Versionen ohn LTO gab es natürlich auch, aber die haben eher ein 
H-Kennzeichen)

> Mal ganz abgesehen davon ist es auch nicht "dreckig", wenn man Dateien
> inkludiert, die nicht auf .h enden. Daß meistens .h-Files inkludiert
> werden, ist natürlich richtig, aber man kann jede Datei inkludieren.
>
> Die Schach-Engine Crafty ist wohl vielen ein Begriff, und die wird
> gebaut, indem in crafty.c alle c-Files mit #include reingezogen werden.
> Im Makefile ist crafty.o das (!) Objektfile. Hintergrund ist bessere
> Performance.
Sowas kann man sich natürlich als Beispiel hernehmen.
Am besten als abschreckendes.

> Wer trotzdem Panik bekommt, kann die Datei ja auch auf .dat enden
> lassen.
Das löst nicht das Problem von doppelten Symbolen oder doppelter 
Flash-Belegung, falls nicht bestimmte Randbedingungen erfüllt sind (nur 
eine Übersetzungseinheit. Wobei die doppelte/n-fache Flashbelegung erst 
mal zu keiner Fehlermeldung führt, nur Platz verschwendet.

von Nop (Gast)


Lesenswert?

Carl D. schrieb:

> Das Code-Beispiel inkludiert <avr.io>, also wohl GCC und damit auch LTO.

GCC und -flto ist embedded keine so tolle Idee, weil dann z.B. 
-fstack-usage nicht mehr funktioniert - die .su-Dateien sind leer.

> Sowas kann man sich natürlich als Beispiel hernehmen.
> Am besten als abschreckendes.

Kann man machen, muß man aber nicht. Rufus' Einwand gegen static, daß 
das nur dem Einhalten von Prinzipien diene, geht natürlich genauso auch 
andersrum, wenn man sich gegen das include von .c-Dateien wehrt.

Sicher wird's unübersichtlich, wenn sich C-Dateien kreuz und quer 
gegenseitig beinhalten, weil man dann nicht mehr weiß, welcher 
Bezeichner eigentlich in welcher Datei sichtbar ist. Aber das ist hier 
ja wohl nicht der Fall, weil eine Lookuptabelle in genau einer C-Datei 
benötigt wird.

Man sollte natürlich schon die Datei mit der Lookuptabelle so benennen, 
daß allein schon aus ihrem Namen die direkte Zugehörigkeit zu der 
relevanten .c-Datei ersichtlich ist.

Ein wesentlicher Grund, wieso man überhaupt eine separate Datei würde 
haben wollen, ist übrigens der, daß diese Datei maschinell generiert 
wird, z.B. nach umfangreicher Vorverarbeitung anderer Daten als Teil des 
Build-Prozesses.

> Das löst nicht das Problem von doppelten Symbolen oder doppelter
> Flash-Belegung

Das hat man bei file-static doch immer. Ist aber kein Problem, weil man 
das schließlich nur dann macht, wenn man das auch nur in einer Datei 
braucht.

von L. N. (derneumann)


Lesenswert?

Diskutiert ihr noch, was die richtige Antwort für mich ist oder wär die 
dann schon dabei gewesen? Ich bin irgendwo bei LTO dann ausgestiegen :-D

Wie immer kann man vielleicht keine allgemein gültige Aussage treffen 
(zumindest nicht so einfach).
Bevor wir hier aber alle zu Gehirnakrobaten werden und wissenschaftlich 
die allgemein gültige Lösung für die ganze Welt und für alle 
Eventualitäten ergründen:

- Sooo komplex ist meine Firmware dann auch nicht
- Ich hab nicht vor, kreuz und quer zu includen
- Es geht mir nur darum, fette char array Würste aus der main.cpp raus 
zubekommen um sie kleiner und übersichtlicher zu machen

Mir scheint das includen einer .h Datei wo die Daten gleich mit 
drinstehen in dem Fall nicht ganz verkehrt, aber auch das direkte 
includen eines .c Files halte ich für eine Lösung in dem Fall... (ist 
das nicht genau dasselbe oder behandelt der Compiler die Files anhand 
ihrer Endungen dann unterschiedlich?)

von Falk B. (falk)


Lesenswert?

@ L. N. (derneumann)

>Bevor wir hier aber alle zu Gehirnakrobaten werden und wissenschaftlich
>die allgemein gültige Lösung für die ganze Welt und für alle
>Eventualitäten ergründen:

Eine vernünftige Einstellung, die man hier viel zu selten sieht.

>- Sooo komplex ist meine Firmware dann auch nicht
>- Ich hab nicht vor, kreuz und quer zu includen
>- Es geht mir nur darum, fette char array Würste aus der main.cpp raus
>zubekommen um sie kleiner und übersichtlicher zu machen

Dann einfach das Ding in ein .c File mit passendem .h File packen, ohne 
static, fertig.


>Mir scheint das includen einer .h Datei wo die Daten gleich mit
>drinstehen in dem Fall nicht ganz verkehrt,

Müll!

> aber auch das direkte
>includen eines .c Files halte ich für eine Lösung in dem Fall... (ist
>das nicht genau dasselbe oder behandelt der Compiler die Files anhand
>ihrer Endungen dann unterschiedlich?)

NEIN!

Eine .h Datei kann man in beliebig vielen anderen Dateien beliebig oft 
per #include einfügen, eine .c Datei NICHT! Und damit meine ich einen 
sauberen Programmierstil! Ja, auch eine .c Datei kann man per #include 
einfügen, das ist aber Murks! Gerade in C sollte man eben NICHT jeden 
Scheiß machten, den die Programmiersprache nicht verhindert! C ist wie 
ein Rasiermesser, sehr scharf aber auch sehr gefährlich. Man sollte 
wissen was man damit macht und NICHT rumgeigeln!

von L. N. (derneumann)


Lesenswert?

Falk B. schrieb:
> Dann einfach das Ding in ein .c File mit passendem .h File packen, ohne
> static, fertig.

Ich probier das mal und schaue mir den Verbrauch im Stack an. Bin mir 
ziemlich sicher, dass ich das wegen dem Stack static gemacht habe (weil 
mir der sonst übergeht). Kann mich aber auch irren, ist schon zu lange 
her...

Danke jedenfalls mal!

von Falk B. (falk)


Lesenswert?

@L. N. (derneumann)

>> Dann einfach das Ding in ein .c File mit passendem .h File packen, ohne
>> static, fertig.

>Ich probier das mal und schaue mir den Verbrauch im Stack an.

Was soll man da ansehen? Dein Array ist eine globale Variable, die im 
Flash landet und bleibt. Stack- und Heap Verbrauch = NULL!

> Bin mir
>ziemlich sicher, dass ich das wegen dem Stack static gemacht habe (weil
>mir der sonst übergeht). Kann mich aber auch irren, ist schon zu lange
>her...

Es irrt der Mensch, solang er lebt .  . .

von L. N. (derneumann)


Lesenswert?

Falk B. schrieb:
> @L. N. (derneumann)
>
>>> Dann einfach das Ding in ein .c File mit passendem .h File packen, ohne
>>> static, fertig.
>
>>Ich probier das mal und schaue mir den Verbrauch im Stack an.
>
> Was soll man da ansehen? Dein Array ist eine globale Variable, die im
> Flash landet und bleibt. Stack- und Heap Verbrauch = NULL!
>
>> Bin mir
>>ziemlich sicher, dass ich das wegen dem Stack static gemacht habe (weil
>>mir der sonst übergeht). Kann mich aber auch irren, ist schon zu lange
>>her...
>
> Es irrt der Mensch, solang er lebt .  . .

Ich hab da static sicher nicht stehen nur weil das in irgendeinem 
Beispiel gestanden ist und der Compiler keine Fehler geworfen hat (oder 
doch..?) ;-)
Aber mag schon sein, dass das nicht wegen Platzverbrauch im Stack war.

von Falk B. (falk)


Lesenswert?

@L. N. (derneumann)

>Ich hab da static sicher nicht stehen nur weil das in irgendeinem
>Beispiel gestanden ist und der Compiler keine Fehler geworfen hat (oder
>doch..?) ;-)

Oder doch?

Meine These. Du hast die .c Datei mehrfach per #include in mehreren 
Dateien eingefügt und damit mehrere Objekte vom gleichen Namen erzeugt. 
Da hat der Linker gemeckert, weil er das nicht auflösen kann. Mit static 
ging es dann, weil jedes Einfügen nur lokale Wirkung und Sichtbarkeit 
(Name) hat. Damit meckert der Linker nicht mehr, aber dein 
Flash-Verbrauch steigt an, weil das Array X-mal eingefügt ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk B. schrieb:
> @ L. N. (derneumann)
>> aber auch das direkte
>>includen eines .c Files halte ich für eine Lösung in dem Fall... (ist
>>das nicht genau dasselbe oder behandelt der Compiler die Files anhand
>>ihrer Endungen dann unterschiedlich?)
>
> NEIN!


Tatsächlich ist das Includen von C-Code garnicht sooo unüblich, z.B. für 
X-Macros. Die zu includende Datei wird dann nicht .c genannt, sondern 
.def o.ä.

Vorteil:
========

— Die Daten können static bzw. lokal sein.

— Bei Daten wie vom TO gebraucht funktioniert sizeof.

— Kein extra Modul .c im Makefile erforderlich.

— Passt gut zu Anwendungsfall, bei dem modul.c handgeschrieben und 
data.def auto-generiert ist.

— C-Quelle modul.c bleibt kleiner und somit besser les- und wartbar.


Nachteil:
=========

— Extra Abhängigkeit im Makefile:  modul.o hängt ab von data.def.

— Paradigme nicht so verbreitet / bekannt wie .c-Module.

— Nichts für Proponenten der "Reinen Lehre".

von Stefan F. (Gast)


Lesenswert?

Eigentlich ist dem Compiler völlig egal, wie die Dateien heißen. Man 
kann seine Quelltexte sogar *.ino nennen (kleiner Seitenhieb).

Die Dateiendung ist eher für den Menschen da, damit er seine Dateien 
sinnvoll gruppieren kann.

Die #include Anweisung macht genau das, was ihr Name bedeutet. Sie 
inkludiert den Inhalt einer Datei an der Stelle, wo die Anweisung steht.

Der Programmierer muss die Anweisung mit Bedacht verwenden. Ich würde 
das Inkludieren von *.c Dateien nicht als grundsätzlich falsch 
verurteilen. Insbesondere in Kombination mit Tools, die Fragmente von 
Quelltext generieren (also keine kompletten *.c Dateien) kann das 
durchaus Sinn ergeben. Aber man sollte schon dreimal darüber nachdenken, 
ob das, was man da gerade vor hat, korrekt ist.

von L. N. (derneumann)


Lesenswert?

Falk B. schrieb:
> @L. N. (derneumann)
>
>>Ich hab da static sicher nicht stehen nur weil das in irgendeinem
>>Beispiel gestanden ist und der Compiler keine Fehler geworfen hat (oder
>>doch..?) ;-)
>
> Oder doch?
>
> Meine These. Du hast die .c Datei mehrfach per #include in mehreren
> Dateien eingefügt und damit mehrere Objekte vom gleichen Namen erzeugt.
> Da hat der Linker gemeckert, weil er das nicht auflösen kann. Mit static
> ging es dann, weil jedes Einfügen nur lokale Wirkung und Sichtbarkeit
> (Name) hat. Damit meckert der Linker nicht mehr, aber dein
> Flash-Verbrauch steigt an, weil das Array X-mal eingefügt ist.

Nö, hatte bisher nur eine main.cpp und da war alles drin, inkl. der 
static Variable die ich nun auslagern will. Ursprünglich wurde also 
nichts included, schon gar nicht mehrfach...
Egal, vergessen wir was war und konzentrieren wir uns auf die Zukunft :D

von Falk B. (falk)


Lesenswert?

@Stefan Us (stefanus)

>Der Programmierer muss die Anweisung mit Bedacht verwenden. Ich würde
>das Inkludieren von *.c Dateien nicht als grundsätzlich falsch
>verurteilen.

Ich schon, vor allem wenn es für ein Problem einen deutlich besseren, 
etablierten Weg gibt.

>Insbesondere in Kombination mit Tools, die Fragmente von
>Quelltext generieren (also keine kompletten *.c Dateien) kann das
>durchaus Sinn ergeben.

Ganz tolle Tools!

> Aber man sollte schon dreimal darüber nachdenken,
> ob das, was man da gerade vor hat, korrekt ist.

Mensch Leute, es geht hier um den NORMALFALL für den Wald- und 
Wiesenprogrammierer!!!

Beitrag "Re: static const PROGMEM in eigenes File auslagern"

Nicht um akademische Ausnahmen!

von Nop (Gast)


Lesenswert?

L. N. schrieb:

> Nö, hatte bisher nur eine main.cpp und da war alles drin

Jetzt wird's richtig dirty talk. ^^

von L. N. (derneumann)


Lesenswert?

Nop schrieb:
> L. N. schrieb:
>
>> Nö, hatte bisher nur eine main.cpp und da war alles drin
>
> Jetzt wird's richtig dirty talk. ^^

naja es war mal eine blabla.ino - ich hab damals meinen kopf schräg 
gehalten und den inhalt da als stream 1:1 hineingeleert. rausgekommen 
ist ein 4000 zeilen .ino file als ich den kopf wieder gerade 
aufgerichtet hab xD

von Einer K. (Gast)


Lesenswert?

Aus meiner Sicht:

Die Deklaration in einer *.h unterbringen
Die Definition in einer *.c, oder im Fall Arduino, in einer *.cpp 
unterbringen.
Die *.h dann in jeder Übersetzungseinheit einbinden, welche auf die 
Daten zugreift.


Was das Ganze mit dem Stack zu tun haben soll, ist mir ein Rätsel.

von Maxim B. (max182)


Lesenswert?

L. N. schrieb:
> Das hier scheint ja nun zu funktionieren auch wenn es nicht ganz sauber
> zu sein scheint

Mag sein, das ist unsauber. Aber bisher habe ich auch immer so gemacht, 
wenn ich lange Tabellen brauche. So bleibt c-Text kürzer und 
verständlicher.

Aber warum immer noch PROGMEM? Es gibt schon const __flash ! Damit kann 
man auch Tabellen von __uint24 und anderen für PROGMEM nicht möglichen 
Varianten machen.

von Einer K. (Gast)


Lesenswert?

Maxim B. schrieb:
> Aber warum immer noch PROGMEM? Es gibt schon const __flash ! Damit kann
> man auch Tabellen von __uint24 und anderen für PROGMEM nicht möglichen
> Varianten machen.

AVR Arduino nutzt Gcc/C++.
Bisher ist mir da __flash noch nicht untergekommen. Wirft Fehler.

Es gibt bisher keine Alternative zu __attribute__((_progmem_)) oder 
PROGMEM. (zumindest ist mir keine bekannt)
Der IAR C Compiler kann das offensichtlich.


Wenn ich mich täusche, dann bitte ich um Aufklärung.
Über ein testbares Beispiel würde ich mich sehr freuen.

von Carl D. (jcw2)


Lesenswert?

Arduino F. schrieb:
> Maxim B. schrieb:
>> Aber warum immer noch PROGMEM? Es gibt schon const __flash ! Damit kann
>> man auch Tabellen von __uint24 und anderen für PROGMEM nicht möglichen
>> Varianten machen.
>
> AVR Arduino nutzt Gcc/C++.
> Bisher ist mir da __flash noch nicht untergekommen. Wirft Fehler.
>
> Es gibt bisher keine Alternative zu __attribute__((_progmem_)) oder
> PROGMEM. (zumindest ist mir keine bekannt)
> Der IAR C Compiler kann das offensichtlich.
>
>
> Wenn ich mich täusche, dann bitte ich um Aufklärung.
> Über ein testbares Beispiel würde ich mich sehr freuen.

__flash ist einer der "named address spaces", die der Avr-GCC 
untestützt. Allerdings nur bei C, nicht bei C++ und damit nicht in 
deinen Fanbereich ;-)

>> Ich probier das mal und schaue mir den Verbrauch im Stack an. Bin mir
>> ziemlich sicher, dass ich das wegen dem Stack static gemacht habe
>> (weil mir der sonst übergeht).
> Was das Ganze mit dem Stack zu tun haben soll, ist mir ein Rätsel.
Das ist ein Kalibrierungssatz.

von Peter D. (peda)


Lesenswert?

Nop schrieb:
> Tip: man kann mit #include auch .c-Dateien inkludieren.

Man kann sich auch einen Knopf an die Backe nähen.

Es gibt aber Regeln, um Programme leichter zu verstehen und weniger 
Fehler zu machen:
Alles, was Speicher belegt (Code, Daten) ist ein *.c-File.
Alles ohne Verbrauch ein *.h-File (auch Inline-Funktionen).
h-Files werden includiert und können das beliebig oft.
c-Files werden übersetzt und mit dem Linker verbunden.

von Nop (Gast)


Lesenswert?

Peter D. schrieb:

> Alles, was Speicher belegt (Code, Daten) ist ein *.c-File.

Eben.

> c-Files werden übersetzt und mit dem Linker verbunden.

Kann man machen, muß man für Datenfiles aber nicht. Wenn man Code nicht 
mehr versteht, weil ein Datenfile inkludiert wird, sollte man sich 
vielleicht ein neues Betätigungsfeld suchen.

von L. N. (derneumann)


Lesenswert?

popcorn und cola hol

von soundso (Gast)


Lesenswert?

hab mal noch einen anderen einwand:

es wird von einem esp8266 als plattform gesprochen und im gleichen 
atemzug wird mit PROGMEM für AVR rumgefuchtelt ...

was hat ein avr mit einem esp8266 gemeinsam? ja genau in der makerscene 
scheinen die ja identisch zu sein, da sie mit der arduino ide beschick 
werden können ...

man man man ...

von Einer K. (Gast)


Lesenswert?

soundso schrieb:
> man man man ...

Mit der "makerscene" kenne ich mich nicht aus!
Aber PROGMEM gibts auch beim ESP (zumindest in der Arduinowelt)

von soundso (Gast)


Lesenswert?

Arduino F. schrieb:
> (zumindest in der Arduinowelt)

keine weiteren fragen ... :-)

von Nop (Gast)


Lesenswert?

soundso schrieb:

> es wird von einem esp8266 als plattform gesprochen und im gleichen
> atemzug wird mit PROGMEM für AVR rumgefuchtelt ...

PROGMEM gibt's auch auf dem ESP8266:
https://espressif.com/sites/default/files/documentation/save_esp8266ex_ram_with_progmem_en.pdf

von soundso (Gast)


Lesenswert?

ok nehm alles zurück und behaupte das gegenteil ... :-)

interessant das sich espresiff and dei gleiche syntax wie beim AVR 
gehalten hat... respekt ...

trotzdem, verstehen was das makro macht, was die sections im linker 
bedeuten,  wo strings oder daten abgelegt werden, was die attribute für 
auswirkungen haben usw ... sollte man oder frau.

spannened auch: das ding hat 160kB Ram total (davon 64kB Sram) und 8kB 
stack anstelle 4kB führen zu instabilitäten? scheint wohl bis aufs 
letzte ausgereizt.

von L. N. (derneumann)


Lesenswert?

mampf

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

soundso schrieb:
> was hat ein avr mit einem esp8266 gemeinsam?

Das Ding ist (zu meiner großen Überraschung) auch harvard :-(

Beitrag #5386475 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

Was allerdings PROGMEM mit dem Stackverbrauch zu tun haben soll, ist mir 
weiterhin nicht klar.

von Nop (Gast)


Lesenswert?

soundso schrieb:

> spannened auch: das ding hat 160kB Ram total (davon 64kB Sram) und 8kB
> stack anstelle 4kB führen zu instabilitäten? scheint wohl bis aufs
> letzte ausgereizt.

Wenn man mehr auf den Stack packt, als man ihn dimensioniert hat, dann 
knallt's genauso wie überall sonst auch. Entweder, man dimensioniert ihn 
dann größer, oder man packt weniger drauf.

von Nop (Gast)


Lesenswert?

Arduino F. schrieb:
> Was allerdings PROGMEM mit dem Stackverbrauch zu tun haben soll,
> ist mir weiterhin nicht klar.

Wenn Du eine Variable in einer Funktion lokal deklarierst, wandert sie 
auf den Stack, auch wenn es eine Konstante ist. Mit PROGMEM wandert sie 
hingegen ins Flash.

von Einer K. (Gast)


Lesenswert?

Nop schrieb:
> Arduino F. schrieb:
>> Was allerdings PROGMEM mit dem Stackverbrauch zu tun haben soll,
>> ist mir weiterhin nicht klar.
>
> Wenn Du eine Variable in einer Funktion lokal deklarierst, wandert sie
> auf den Stack, auch wenn es eine Konstante ist. Mit PROGMEM wandert sie
> hingegen ins Flash.

Naja, lokale statische Variablen verbrauchen keinen StackSpace.
Und zu Anfang ging es um globale Daten.
Also auch kein StackVerbrauch.

Lokale Variablen ins Flash stopfen?
OK...
Wers braucht...

Meinen Segen.

von Nop (Gast)


Lesenswert?

Arduino F. schrieb:

> Naja, lokale statische Variablen verbrauchen keinen StackSpace.
> Und zu Anfang ging es um globale Daten.
> Also auch kein StackVerbrauch.

Das haben vor Dir schon zwei Poster erwähnt.

> Lokale Variablen ins Flash stopfen?
> OK...
> Wers braucht...

Lokal heißt nicht Stack oder Flash, weil C das gar nicht spezifiziert, 
sondern es geht um minimales Scoping.

von Karl (Gast)


Lesenswert?

Peter D. schrieb:
> Alles, was Speicher belegt (Code, Daten) ist ein *.c-File.
> Alles ohne Verbrauch ein *.h-File (auch Inline-Funktionen).

Man kann auch Code komplett in h-Files schreiben, und nur die main als 
c-File.

Dieses Springen zwischen h und c, für jede Unit zwei Dateien auf der 
Platte und im Editor halten, aufpassen dass sie konsistent bleiben... 
finde ich eine der nervigsten Sachen bei C. Und es gibt vieeele nervige 
Sachen bei C.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Karl schrieb:
> Dieses Springen zwischen h und c, für jede Unit zwei Dateien auf der
> Platte und im Editor halten, aufpassen dass sie konsistent bleiben...
> finde ich eine der nervigsten Sachen bei C. Und es gibt vieeele nervige
> Sachen bei C.

Ach, du schon wieder :-)

Vermutlich kommst du dann wieder mit einem Beispiel, wo sich nachher 
herausstellt dass du (absichtlich?) mit -O0 kompiliert hast, und wenn 
man dir das nachweist, du schön still bist...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Karl schrieb:
> finde ich eine der nervigsten Sachen bei C.

Man kann natürlich auch versuchen, sich komplett dem Erlernen des 
genutzten Werkzeugs zu verweigern und alles als "nervig" zu bezeichnen, 
was man nicht versteht.

von Curby23523 N. (Gast)


Lesenswert?

Karl schrieb:
> Und es gibt vieeele nervige
> Sachen bei C.

Wo ist das Problem? Wenn ich z.B. einen CANopen-Stack programmiere, 
erstelle ich eine Header und mehrere C-Files, wo dann nach Bereichen und 
Dateinamen sortiert der Sourcecode des Stacks untergebracht ist.

Brauche ich nun in einer anderen Source CANopen Funktionalität, dann 
muss ich nur den Header inkludieren.

Genauso geht das doch auch bei PROGMEM. Im Header die Variable 
ankündigen und wo anders niederschreiben. Ich habe meine Lookup Tabellen 
immer in einer separaten C-Datei z.B. ein LCD-Font. font.h und font.c, 
als ich noch einen Xmega verwendet habe mit PROGMEM, bei STM32 mit const 
- wenn global brauche ich sowieso kein static, ich will ja von überall 
hierauf zugreifen. Dort, wo ich den Font gebraucht habe, einfach die 
font.h inkludieren, fertig. Der Lookup Source kann dann dort vergammeln, 
die C-Datei wird so gut wie gar nicht mehr angesehen.

.c inkludieren geht dermaßen an der Idee vorbei, das ist 
unbeschreiblich.

von Karl (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Man kann natürlich auch versuchen, sich komplett dem Erlernen des
> genutzten Werkzeugs zu verweigern

Man kann auch ein Werkzeug, welches einem zu umständlich ist weglegen 
und sich eines greifen, mit dem man besser zu seinem Ergebnis kommt.

Dumm halt, dass in diesem Forum C allgemein als alternativlos 
dargestellt wird - und ich das leider einige Zeit geglaubt und mich mit 
diesem Werkzeug herumgequält habe.

Dass das Konzept der c und h Dateien nicht ganz so schlüssig ist, wie 
einige glauben, sieht man ja hier im Thread.

Oder "inline Prozeduren kommen in die h". Was, wenn die nicht mehr 
inline sein sollen, weil Aufruf speichersparender ist als sie jedesmal 
einzubauen? Fang ich dann an, sie in die c zu kopieren?

Oder Konstanten, werden in der h deklariert. Aber dann doch direkt im 
Code eingebaut.

von Curby23523 N. (Gast)


Lesenswert?

Karl schrieb:
> Man kann auch ein Werkzeug, welches einem zu umständlich ist weglegen
> und sich eines greifen, mit dem man besser zu seinem Ergebnis kommt.

Was benutzt du denn oder hast du vor zu benutzen?

Karl schrieb:
> Oder Konstanten, werden in der h deklariert. Aber dann doch direkt im
> Code eingebaut.

Wenn sie als const deklariert werden heißt das zuallererst, dass diese 
Variablen nicht verändert werden dürfen. Intelligente Compiler legen 
diese dann in den Flash. Bei Atmel Studio muss man halt mit PROGMEM den 
Compiler dazu anweisen.

Karl schrieb:
> Dumm halt, dass in diesem Forum C allgemein als alternativlos
> dargestellt wird - und ich das leider einige Zeit geglaubt und mich mit
> diesem Werkzeug herumgequält habe.

Nicht alternativlos, aber der absolute Standard für Programmierung von 
Mikrocontrollern.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Curby23523 N. schrieb:
> Was benutzt du denn oder hast du vor zu benutzen?

Lass ihn. Karl spielt in der Liga von c-hater (oder ist c-hater). 
Einfach ignorieren, alles andere führt zu nichts.

von Karl (Gast)


Lesenswert?

Curby23523 N. schrieb:
> Variablen nicht verändert werden dürfen. Intelligente Compiler legen
> diese dann in den Flash.

Quatsch. Konstanten werden direkt in den Code eingebaut und mit LDI 
geladen. Damit liegen sie zwar im Flash, aber mit Progmem hat das gar 
nichts zu tun.

Verwechselst Du das mit Strings oder Lookup-Tables?

Curby23523 N. schrieb:
> der absolute Standard für Programmierung von
> Mikrocontrollern.

Du darfst nicht Alles glauben, was Dir hier im Forum erzählt wird.

von Curby23523 N. (Gast)


Lesenswert?

Karl schrieb:
> Quatsch. Konstanten werden direkt in den Code eingebaut und mit LDI
> geladen. Damit liegen sie zwar im Flash, aber mit Progmem hat das gar
> nichts zu tun.

Ich weiß, es ist sinnlos.
1
const uint8_t u8Bla = 0x12;

Diese Variable ist erstmal lediglich eine Konstante und darf nicht 
geändert werden. Wenn ich jetzt gemein bin und den Compiler ausspielen 
möchte kann ich auf diese Variable zugreifen über einen Zeiger und sie 
dennoch verändern, sofern diese als Variable im RAM liegt. Und das ist 
der Knackpunkt. Für µC wird diese Variable auf Platzspargründen auf den 
Flash gelegt. Das ist logisch.
1
main()
2
{
3
  const int  Men   = 10;
4
  int       *Women = &Men;
5
6
  *Women = 20;
7
8
  printf("There are %d men\n", Men);
9
  
10
}

Das hat aber nichts mit CONST zu tun. Das ist die Entscheidung bzw. 
Voreinstellung des Compilers/Linkers. Das Schlüsselwort CONST 
entscheidet per se nicht darüber, wo diese variable abgelegt wird.

Karl schrieb:
> Du darfst nicht Alles glauben, was Dir hier im Forum erzählt wird.

Nämlich? BASIC? Assembler (damit kannst du kein Geld mehr verdienen)? 
Java ;)? Pascal? C#? .Net? JavaScript? LabView? CubeMX (ein Klick und 
alles ist fertig programmiert - leider in C) ?

von Nop (Gast)


Lesenswert?

Curby23523 N. schrieb:
> Wenn ich jetzt gemein bin und den Compiler ausspielen
> möchte kann ich auf diese Variable zugreifen über einen Zeiger und sie
> dennoch verändern, sofern diese als Variable im RAM liegt.

Das darf der Compiler getrost ignorieren, solange Du das nicht als const 
volatile deklarierst.

von Stefan F. (Gast)


Lesenswert?

> Dieses Springen zwischen h und c ...
> finde ich eine der nervigsten Sachen bei C.

Dann schau Dir mal SAP Hybris an (ein Online Shop), der wurde in Java 
geschrieben. Das ist die Programmiersprache, deren Entwickler sich auf 
die Fahne geschrieben hatten, alle schlechten Sachen von C/C++ entweder 
weg zu lassen oder durch viel bessere Konstrukte zu ersetzen.

Bei SAP Hybris bekommst du eine closed-source Basis-Software, die du 
durch zahlreiche (ich nenne sie mal) Module ergänzen musst, damit daraus 
ein vollständiges Programm wird. Damit man diese Module compilieren kann 
liefert SAP unvollständige und veraltete Java-Quelltexte der Basis mit. 
In der Eclipse IDE wird alles Mögliche rot markiert, obwohl es doch "in 
Ordnung" ist. Soll das etwa besser sein?

In C/C++ hätte SAP einfach die Header Dateien der Schnittstellen 
veröffentlichen können. In Java scheint es (trotz Spring Framework) 
keinen ausreichenden Ersatz zu geben, sonst hätte SAP es besser gemacht.

von Karl (Gast)


Lesenswert?

Curby23523 N. schrieb:
> Für µC wird diese Variable auf Platzspargründen auf den
> Flash gelegt.

Nee. Nie im Leben.

Wenn die Variable "auf dem Flash" liegen würde, müsste die Zuweisung 
über den Pointer SCHREIBEND auf den Flash zugreifen. Mit SPM und den 
entsprechenden Schreibrechten, Schreibzeiten.

Das glaub ich erst, wenn Du mir das Assemblerlisting zeigst. Was ist mit 
Schreibschutz, AVRs die kein SPM können?

Auf dem uC wird die Variable als Register oder im Sram geführt und per 
LDI gefüllt. Dabei steht der Wert hinter LDI zwar auch im Flash, ist 
dort aber nicht veränderlich. Und hat mit Progmem nichts zu tun, der 
Zugriff auf Progmem-Konstanten (Strings, Tables) läuft über LPM.

von Curby23523 N. (Gast)


Lesenswert?

"A const qualified type indicates that access to the designated data
object cannot alter the value stored in the data object. All other data
objects can have their values altered".

Wo ein const hin wegoptimiert wird (LDI oder Flash..) und ob große 
Lookup Tables im Flash landen, ist Sache des Compilers oder zusätzlicher 
Anweisungen an diesen (PROGMEM). Ich kann mir vorstellen, dass ganz ohne 
Optimierung das knallhart als Variable abgelegt wird. In C++ ist const 
ja etwas anders, als in C. Vermutlich macht hier aber bereits der gcc 
einen Strich durch die Rechnung.

Aber nur darum geht es. Const hat nichts damit zu tun, wo eine Variable 
oder Lookup landet, in keinster Weise. Aber natürlich sieht nahezu jeder 
Compiler "Hey eine arme Variable const? Direkt als Konstante in den 
Programmcode damit!". Ob nun ein const uint8_t Array[2] oder erst ein 
const uint8_t Array[2000] als Lookup im Flash landet, darüber können die 
Studenten der Eliteuni TU München debattieren ;). Bei ARM z.B. weiß ich, 
dass const uint8_t Array[2000] im Flash landet.

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.