Forum: Mikrocontroller und Digitale Elektronik Alternativen zu C, C++ auf ARM cortex M?


von Programierer (Gast)


Lesenswert?

Hallo,

welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen, 
die auch mit wenig ram&rom (4kB/32kB) auskommt?

Die allgegenwärtigen libs (in C geschrieben!) sollte man aber noch 
weiter verwenden können.

(Ich habe über die Jahre eine leichte C-Allergie entwickelt, die auch 
bei C++ und ähnlichen auftritt)

von Einer K. (Gast)


Lesenswert?

Ich würde dir eine Desensibilisierung empfehlen...

von Jim M. (turboj)


Lesenswert?

Arduino F. schrieb:
> Ich würde dir eine Desensibilisierung empfehlen...

Entweder das oder gleich Assembler schreiben. Bei nur 4kB RAM kennt man 
noch jedes Byte mit Namen.

ARM Cortex-M an sich ist aber für C-Compiler optimiert.

Es ist auch in Assembler nicht übermäßig schwierig C-Libraries zu 
benutzen, aber die müssten erstmal in das enge RAM und Flash Korsett 
passen...

von Markus F. (mfro)


Lesenswert?

wie wär's mit Ada?

https://www.adacore.com/download

von u8g2 (Gast)


Lesenswert?

Selbst wenn es eine andere Programmiersprache gäbe, dann fehlen meist 
noch die Registerbeschreibungen, Bitkonstanten u.ä. wie man sie 
üblicherweise in den C-Include-Dateien der Hersteller findet.

Aber vielleicht ist das ja ganz interessant:

http://blog.japaric.io/quickstart/

Oliver

von Nop (Gast)


Lesenswert?

Programierer schrieb:

> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?

Free Pascal, weil C-Allergiker oftmals Pascal mögen.

von Axel S. (a-za-z0-9)


Lesenswert?

Programierer schrieb:
> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?

Das hängt nur sehr wenig von der Programmiersprache ab, sondern im 
wesentlichen von der Qualität des Compilers. 32K Flash und 2K RAM 
reichen auch in C für sehr viele Dinge aus.

> Die allgegenwärtigen libs (in C geschrieben!) sollte man aber noch
> weiter verwenden können.

Dann wäre ein C-Compiler die kanonische Wahl. Obwohl natürlich auch 
viele andere Sprachen mit C-Linkage umgehen können. Notfalls sogar 
Assembler, obwohl das eher Masochismus ist als alles andere.

Aber deiner Intention, Speicher zu sparen, entspricht das nicht. Denn 
das, was ein C-Programm typischerweise fett macht, sind eben die 
verwendeten Libraries.

> (Ich habe über die Jahre eine leichte C-Allergie entwickelt, die auch
> bei C++ und ähnlichen auftritt)

Dann wünsche ich baldige Genesung. Gesund ist das nämlich nicht.

von Oliver J. (skriptkiddy)


Lesenswert?

Programierer schrieb:
> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?

Hier würde ich die GCC einsetzen mit wahrscheinlich stark 
eingeschränktem C++.

... manchmal im Leben gibt es einfach keine sinnvollen Alternativen ;)

Grüße Oliver

von Rainer S. (rsonline)


Lesenswert?


von Lothar (Gast)


Lesenswert?


von Nase (Gast)


Lesenswert?

Rainer S. schrieb:
> https://www.mikroe.com/mikropascal/#arm

Finger weg...

Das Drumherum von Mikroelektronika (Boards, Bibliotheken, IDE usw.) ist 
wirklich hübsch eingerichtet und es macht echt Spaß, damit zu basteln.

Die Compiler würde ich mir aber genau angucken, bevor ich damit 
professionell loslege. Zumindest die AVR-Compiler sind/waren unter aller 
Sau(*), inklusive lächerlichem Optimierer und extrem subtilen Bugs(**).

In die mitgelieferten Bibliotheken kann man halt größtenteils nicht 
reingucken.

(*) Der optimiert meistens garnix, aber wenn, dann auch mal 
versehentlich großzügig Teile des Programms weg...
(**) Konkret hat der C-Compiler an verschiedenen Stellen ein 
char-Argument nicht zu int promoted, wie es im Standard gefordert ist.

von Programierer (Gast)


Lesenswert?

Markus F. schrieb:
> wie wär's mit Ada?
>
> https://www.adacore.com/download

Interessant.

Ich hab hier viele libXYZ.a und dazu passende XYZ.h
Wie kann ich die weiterhin verwenden?
Ein "use XYZ.h;" (oder so ähnlich) geht wohl nicht..

von Einer K. (Gast)


Lesenswert?

Die *.h Dateien, wirst du wohl in ADA Packages umschreiben dürfen.
Dann sollte es auch mit deinen *.a klappen.
-- Ungetestet (bin nicht so der ADA Spezi)

Jedes gute ADA Buch sollte einen Abschitt "Interfacing to Other 
Languages", o.ä. beinhalten.

von Axel S. (a-za-z0-9)


Lesenswert?

Arduino F. schrieb:
> Die *.h Dateien, wirst du wohl in ADA Packages umschreiben dürfen.

Das ist nur die halbe Miete.

> Dann sollte es auch mit deinen *.a klappen.

Das ist nicht gesagt. Dazu muß der ADA-Compiler entweder das gleiche ABI 
(Aufrufkonvention, Typcodierung) benutzen wie der C-Compiler oder es 
zumindest als Variante unterstützen.

von Mike (Gast)


Lesenswert?


von Stefan S. (Gast)


Lesenswert?

u8g2 schrieb:
> Selbst wenn es eine andere Programmiersprache gäbe, dann fehlen meist
> noch die Registerbeschreibungen, Bitkonstanten u.ä. wie man sie
> üblicherweise in den C-Include-Dateien der Hersteller findet.

Ja. Jemand der nicht zur Fraktion "Dumm, faul und gefräßig" zählt würde 
womöglich auch über den Einsatz von Nim nachdenken. Einige Leute hatten 
damit im Embeded-Bereich ja schon experimentiert. Aber

>wenig ram&rom (4kB/32kB)

ist schon extrem wenig.

von Stefan F. (Gast)


Lesenswert?

Ich hatte damals als Schüler das Programmieren in Pascal gelernt.

Die Windows API war in C geschrieben, jedoch hatte Borland sie 
weitgehend in Pascal Libraries gekapselt.

Der Haken war, dass die Dokumentation dieser Kapselungen stets veraltet 
und oft unvollständig war. Dazu kam, dass ich gelegentlich Windows 
Features nutzen wollte, die Pascal nicht gekapselt hatte.

Zum Beispiel wollte ich damals den Status eines Fensterlosen Programmes 
(IR Empfänger) mit einem Taskleisten-Icon in der rechten unteren Ecke 
anzeigen.

So wurde ich gezwungen, ziemlich oft in die API Dokumentation von 
Microsoft zu schauen. Dort fand ich oft auch oft hilfreiche 
Programmbeispiele, aber eben immer nur in C (manhcmal auch C++).

So musste ich gezwungenermaßen auch wenigstens ein bisschen C und C++ 
lernen. Und als ich so weit war, fragte ich mich "Warum programmiere ich 
eigentlich in Pascal"?

Mir fielen nur wenige starke Argumente für Pascal ein. Deswegen 
wechselte ich nach C/C++ obowhl das technisch gesehen ein Rückschritt 
war und die Sprache definitiv hässlicher ist. Trotzdem bin ich bis heute 
dabei geblieben und hatte nie das Gefühl, dabei auf dem Holzweg zu sein.

Nun programmiere ich nur noch selten Windows/Linux Programme, dafür mehr 
Mikrocontroller. Dass man die auch in C/C++ programmieren kann, erwies 
sich für mich als äußerst praktisch. Nach wie vor sind diese Sprachen 
mit hässlichen Details durchsetzt, aber das ist für mich noch lange kein 
Grund, sie nicht zu benutzen.

Egal welche andere Sprache zu benutzt, du wirst dich trotzdem auch mit C 
auseinander setzen müssen. Alleine schon wegen der Libraries.

von c-hater (Gast)


Lesenswert?

Stefan U. schrieb:

> Egal welche andere Sprache zu benutzt, du wirst dich trotzdem auch mit C
> auseinander setzen müssen. Alleine schon wegen der Libraries.

Genauso ist das. Man muss C nicht lieben, aber man muss es trotzdem 
beherrschen, wenn man in dieser Welt programmiermässig mit dem Arsch an 
die Wand kommen will.

Und natürlich: Es läßt sich auch viel besser über Sachen lästern, die 
man kennt und gerade deswegen hasst, weil man sie kennt. ;o)

von Dr. Sommer (Gast)


Lesenswert?

c-hater schrieb:
> Man muss C nicht lieben, aber man muss es trotzdem
> beherrschen, wenn man in dieser Welt programmiermässig mit dem Arsch an
> die Wand kommen will.
In der Systemprogrammierung vielleicht. Bei normaler 
PC/Server-Anwendungs- oder Web-Entwicklung kann man gut ohne auskommen.

Stefan U. schrieb:
> Deswegen
> wechselte ich nach C/C++ obowhl das technisch gesehen ein Rückschritt
> war und die Sprache definitiv hässlicher ist.
C und C++ so über einen Kamm zu scheren ist etwas gemein, schließlich 
ist C++ vielfach mächtiger. C++ hat einen Gutteil seiner Hässlichkeit 
aus C geerbt und der bezieht sich hauptsächlich auf die Syntax, und die 
ist weiter hinten auf der Lernkurve eh nicht mehr so wichtig. Dafür kann 
C++ auch mehr als Pascal...

von Johannes S. (Gast)


Lesenswert?

Ich habe früher in PL/M programmiert, das ist irgendwo zwischen C und 
Assembler. Bin aber froh das ich das nicht mehr brauche, ein bisschen 
Luxus möchte man beim Programmieren ja schon haben.
Und das ist doch eher der Punkt, man benutzt C oder C++ um einen höheren 
Abstraktionslebel zu haben und besser lesbare, wartbare und erweiterbare 
Software zu bekommen. C/C++ sind schon sehr effizient mit den modernen 
Compilern, ein Register = 0x1234 wird auch zu wenigen Bytes 
Maschinencode.
Dann hängt die Programmgrösse weniger von der Sprache ab als vielmehr 
von den
Bibliotheken die ich dazupacke. Wenn ich den Komfort eines printf(), 
vielleicht sogar noch mit float Unterstüzung haben möchte, dann kostet 
das halt ein paar kB mehr. Das Schöne bei den Cortex-M ist doch gerade 
das die in ihren Familien viele Geschwister haben und man mit wenig 
Aufwand einen Controller mit mehr Dampf auswählen kann. 256 kB Flash 
bekommt man auch für 2€, warum da alles abspecken und dem 
Performancegott opfern?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> [...] schließlich ist C++ vielfach mächtiger [als C].

Papperlapapp, C++ ist nicht mächtiger als C oder Assembler:  sind alle 
"nur" Turing-vollständig.  *wegduck*

von Dr. Sommer (Gast)


Lesenswert?

Johann L. schrieb:
> Papperlapapp, C++ ist nicht mächtiger als C oder Assembler:  sind alle
> "nur" Turing-vollständig.  *wegduck*
Mit dem Argument kannst du auch gleich in Brainfuck programmieren...

von W.S. (Gast)


Lesenswert?

Programierer schrieb:
> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?

Leider gar keine.

Es hat sich C mittlerweile zu einer Monokultur entwickelt und 
Alternativen sind nicht in Sicht.

Es haben die Leute von Mikroe mal versucht, mit Basic und Pascal zu 
landen, aber sie haben es falsch angestellt, nämlich so, daß ihr Produkt 
eben nicht vom Anwender auf einen µC eingerichtet werden kann, der nicht 
bereits in der Liste der unterstützten Chips steht.

Hätten sie lediglich zwischen den Architekturen (M0...M4F..M7) 
unterschieden und all die Registeranpassungen einfach in einen 
Hardwareunit (für C-Leute: sowas wie "LPC408x.h") gepackt, dann hätten 
diese Compiler eine Anwender-Basis bekommen können. Die Sprache gibt's 
ja her:
1
was in C so lautet:
2
#define NVIC_ISPR     (*((volatile unsigned long *)   (0xE000E200)))
3
4
wäre in Pascal etwa so:
5
NVIC_ISPR : dword absolute $E000E200;
easy, gelle? aber leider eben nicht zu kriegen.

W.S.

von Markus F. (mfro)


Lesenswert?

Axel S. schrieb:
> Arduino F. schrieb:
>> Die *.h Dateien, wirst du wohl in ADA Packages umschreiben dürfen.
>
> Das ist nur die halbe Miete.
>
>> Dann sollte es auch mit deinen *.a klappen.
>
> Das ist nicht gesagt. Dazu muß der ADA-Compiler entweder das gleiche ABI
> (Aufrufkonvention, Typcodierung) benutzen wie der C-Compiler oder es
> zumindest als Variante unterstützen.

Der Ada gnat-Compiler ist Teil der GCC. gcc und gnat stammen also aus 
demselben Stall und kennen sich. Wie man C-Funktionen von Ada aus 
aufruft (und umgekehrt) steht hier: 
https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gnat_ugn/Interfacing-to-C.html

Fertig ist man damit allerdings längst nicht. Die gnat runtime gibt es 
fertig nur für bestimmte ausgesuchte Boards. Andere benötigen wenigstens 
eine rudimentäre Portierung -> 
http://blog.adacore.com/porting-the-ada-runtime-to-a-new-arm-board. Das 
dürfte für so ein "kleines" Board relativ simpel sein - viel Runtime 
passt da ja gar nicht drauf.

von Wilhelm M. (wimalopaan)


Lesenswert?

Programierer schrieb:

> (Ich habe über die Jahre eine leichte C-Allergie entwickelt, die auch
> bei C++ und ähnlichen auftritt)

Ich würde Dir empfehlen, alles was Du bisher über C++ weißt, weg zu 
werfen und statt dessen modernes C++ mit viel moderner TMP neu(!) zu 
erlernen. Um C als common-ground kommst Du leider nicht herum ...

von Pete K. (pete77)


Lesenswert?

Programierer schrieb:
> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?

Wenn Dein Programm zu groß wird, dann nimm doch einfach einen größeren 
Cortex-M. Da gibt es nun wirklich genug Auswahl für jeden Geschmack.

Deine Anfrage ist sehr unspezifisch. Ein "Blinky" Programm passt immer 
in 4kB/32kB, oder meinst Du, dass der Compiler/Linker mit 4kB/32kB 
auskommen muss?

von Programierer (Gast)


Lesenswert?

Die gcc-Monokultur hat auch Vorteile:

Ein '-fdump-ada-spec' macht aus .h .ads

Ein schwer lesbares .h wird dardurch nicht lesbarer - aber ich 
'with/use' es ja nur?


Oliver schrieb:
>http://blog.japaric.io/quickstart/

Danke! Die Rust Leute haben das gleiche Problem:

keine Registerbeschreibungen, keine Bitkonstanten..

von Programierer (Gast)


Lesenswert?

Programierer schrieb:

> keine Registerbeschreibungen, keine Bitkonstanten..

..und wenn man die Seite nicht nur überfliegt, kann man lernen dass es 
für sehr viele MCUs *.svd files gibt und mit "svd2$SPRACHE" diese 
übersetzen kann:)

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Programierer schrieb:

> (Ich habe über die Jahre eine leichte C-Allergie entwickelt, die auch
> bei C++ und ähnlichen auftritt)

was stört Dich den an C, was Du hoffst, in anderen Sprachen zu finden? 
Wie sieht es mit Ada und Rust aus?

: Bearbeitet durch User
von Lothar (Gast)


Lesenswert?

> BASIC

Es wird sogar asymmetrisches Multitasking mit Cortex-M Dual-Core 
unterstützt.

Schaut mal auf die Memory Map:

http://www.coridium.us/ARMhelp/index.htm#page=HWlpc54102.html

von (Gast)


Lesenswert?

es gäbe auch noch forth, das kommt wirklich mit wenig RAM/ROM aus.

https://github.com/jeelabs/mecrisp-stellaris läuft anscheinend schon mit 
16kb flash und 1kb ram.

Terminalprogramm für eine serielle Schnittstelle ist üblicherweise alles 
was man braucht, compiler und entwicklungsumgebung ist in den 16k 
inkludiert.

von Nop (Gast)


Lesenswert?

Torsten R. schrieb:

> was stört Dich den an C, was Du hoffst, in anderen Sprachen zu finden?

Unschön ist die Unmenge an undefined behaviour, besonders weil der 
Compiler dann halt "irgendwas" macht, aber garantiert nichts Nützliches. 
Das wird obendrein schlimmer, weil wegen angeblicher Performancegewinne 
solche UBs auf einmal beim Optimieren genutzt werden, was früher nicht 
der Fall war. Nicht, daß man dadurch wirklich schnelleren Code hätte, 
aber haufenweise reifgetestete Codebasen zeigen sich auf einmal doch 
buggy.

Klar kann man sagen, der Programmierer muß wissen, was er macht, aber 
"design for safety" ist ein grundlegendes Engineering-Prinzip, das 
zumindest für Debug-Builds automatisch möglich sein sollte.

Dann die z.T. unsinnige Operatoren-Rangfolge (z.B. ist & niedriger als 
==), die Integer-Promotion ist auch immer wieder ein Quell der Freude, 
und Arrays zerfallen bei Aufruf an Funktionen zu Pointern, so daß 
automatische Längenchecks nicht optional eincompilierbar sein können.

Dann sind da noch die haarsträubenden Library-Funktionen besonders rund 
ums Stringhandling, die auch mit den n-Versionen (strncpy) immer noch 
Händchenhalten brauchen, weil der resultierende String u.U. nicht 
nullterminiert ist.

Bis hin zu völlig überflüssigen Späßen wie daß das Ergebnis von 
malloc(0) implementationsabhängig ist, was zur Fehlerbehandlung blöd 
werden kann. Überhaupt, wieso kriegt free() nicht einen Pointer auf 
einen Pointer, um den automatisch zu nullen? Dann hätte man bei "use 
after free" automatisch zu einem Crash, was leicht zu entdecken wäre.

Also ich mag C, mehr als Pascal jedenfalls, aber C hat schon seine 
unschönen Seiten.

von Brille (Gast)


Angehängte Dateien:

Lesenswert?

Lothar schrieb:
> BASIC

Hm .. die IDE wirkt wie ein mal schnell so zur Übung zusammengeklickter 
Dialog aus VC. Wenig vertrauenserweckend.

Die Mathe-Funktionen der Runtime Library sind wohl ebenfalls 
"überschaubar".

Kann es sein, dass das Produkt noch nicht ganz ausgereift ist?

;-)

von Thomas E. (picalic)


Lesenswert?

W.S. schrieb:
> was in C so lautet:
> #define NVIC_ISPR     (*((volatile unsigned long *)   (0xE000E200)))
>
> wäre in Pascal etwa so:
> NVIC_ISPR : dword absolute $E000E200;

Und wo ist da das Pascal-Pendant zu "volatile"?

von Brille (Gast)


Lesenswert?

Nase schrieb:
> Rainer S. schrieb:
>> https://www.mikroe.com/mikropascal/#arm

> Das Drumherum von Mikroelektronika (Boards, Bibliotheken, IDE usw.) ist
> wirklich hübsch eingerichtet und es macht echt Spaß, damit zu basteln.

Na, das ist doch schon mal was. Wenn man die IDE mit der von der oben 
erwähnten BASIC Variante vergleicht, tun sich da doch Welten auf.

> Die Compiler würde ich mir aber genau angucken, bevor ich damit
> professionell loslege. Zumindest die AVR-Compiler sind/waren unter aller
> Sau(*), inklusive lächerlichem Optimierer und extrem subtilen Bugs(**).

Ist dein Wissen dazu überhaupt noch aktuell? Oder sind die Bugs 
vielleicht schon längst fehlerbereinigt ..

> In die mitgelieferten Bibliotheken kann man halt größtenteils nicht
> reingucken.

Wollen doch viele Anwender vielleicht auch gar nicht. Sie wollen die 
Libs einfach nur benutzen und damit schnell Ergebnisse erzielen.

> (*) Der optimiert meistens garnix,

Muss wirklich JEDES Codeschnipsel immer "hoch optimiert" sein? Sind wir 
nicht längst aus dem Zeitalter der "ich muss noch ein paar Bytes mehr 
rausquetschen" Analogie herausgewachsen?

> aber wenn, dann auch mal
> versehentlich großzügig Teile des Programms weg...

Wäre nicht schön. Aber ist das wirklich noch so? Die verkaufen doch ihre 
Lizenzen nicht erst seit gestern.

> (**) Konkret hat der C-Compiler an verschiedenen Stellen ein
> char-Argument nicht zu int promoted, wie es im Standard gefordert ist.

Bugs eben. Wie viele Bugs haben Compiler noch mal (generell und quasi 
immer)? Ein paar Dutzend, ein paar hundert, ein paar Tausend?

von Nop (Gast)


Lesenswert?

Thomas E. schrieb:

> Und wo ist da das Pascal-Pendant zu "volatile"?

Pascal hat kein volatile.

> In FPC, every statement is basically considered to be a compiler-level
> memory barrier for accesses to global variables. So within a single
> statement multiple accesses can be optimised, but that cannot happen not
> across statements. It's not perfect since it inhibits some optimisation,
> but on the flip side it's very simple and easy to reason about.

Quelle:
http://lists.freepascal.org/pipermail/fpc-pascal/2015-December/046057.html

von Stefan F. (Gast)


Lesenswert?

> Unschön ist die Unmenge an undefined behaviour

In C ist alles nötige sehr genau definiert. "undefined behaviour" 
provoziert man nur, indem man etwas macht, was nicht vorgesehen ist. Und 
dann bekommt man vom Compiler eine deutliche Warnung.

> auf einmal beim Optimieren genutzt werden

Es steht Dir frei, den Optimierungs-Grad selbst einzustellen. Neue 
Optimierungen kommen immer nur in die höchste Stufe oder in eine neue 
Stufe. Du kannst die Optimierung auch ganz deaktivieren und ggf. manuell 
optimieren, wenn Dir das eher zusagt.

Das alles sind aber nicht C spezifische Probleme. Das kann Dir in jeder 
beliebigen Programmiersprache ebenso passieren. Ich meine z.B. Java, da 
hast du obendrein noch viel weniger Einflussmöglichkeiten.

> "design for safety"

Das ist nicht das primäre Ziel der Sprache C. Allerdings kannst du den 
Optimizer deaktivieren und alle Warnungen aktivieren, dann bist du ganz 
nahe an der Anforderung dran.

> die z.T. unsinnige Operatoren-Rangfolge

Hm die ist bei fast allen Programmiersprachen ebenso. Und ich finde sie 
durchaus sinnvoll.

Deine weiteren Kritikpunkte wurden längst durch C++ und zahlreiche 
andere Programmiersprachen ausgemerzt. Aber diesen Luxus bezahlt man mit 
geringerer Performance und mehr Speicherbedarf.

Offensichtlich gibt es aber noch genug Fälle, wo man eben diese "Kosten" 
nicht toleriert, sonst wäre C schon lange tot.

Was die Library angeht: Du musst sie nicht benutzen. Schreibe Dir eine 
eigene!

> die ... immer noch Händchenhalten brauchen

Du musst die alten Funktionen/Libraries ja nicht benutzen.

Wenn ich heute mit einem Trabbi über die Autobahn knattere, kann ich 
mich auch nicht darüber beklagen, dass manche Auto immer noch so lahm 
und laut sind.

> Bis hin zu völlig überflüssigen Späßen wie daß das Ergebnis
> von malloc(0) implementationsabhängig ist

Du wirfst da zu viel ein eine Topf. Malloc holt sich Speicher vom OS. 
Also hängt das Verhalten von Malloc direkt von OS ab. Wenn du das nicht 
willst, musst du eine eigene Speicherverwaltung nehmen, so wie Java es 
tut. Gibt es übrigens auch für C.

Nur wundere Dich dann nicht, dass jedes kleine Popel-Programm per 
default erstmal etwa die Hälfte des RAM zu belegen versucht. 
Glücklicherweise vergibt Windows inzwischen nur noch virtuellen 
Speicher, so dass das kaum noch auffällt. Aber ich weiß noch, wie das 
unter Windows 3.11 und 95 lief.

> Also ich mag C ... aber C hat schon seine unschönen Seiten.

Da stimme ich Dir allerdings zu. Das trifft sicher auf jede Sprache zu. 
Ich arbeite beruflich viel mit Java, der Sprache, die angeblich alles 
besser machen sollte. Pustekuchen! Java hat genau so viele Fallstricke.

von Dr. Sommer (Gast)


Lesenswert?

Brille schrieb:
> Bugs eben. Wie viele Bugs haben Compiler noch mal (generell und quasi
> immer)? Ein paar Dutzend, ein paar hundert, ein paar Tausend?
Beim GCC sind derzeit mehr als 10000 bekannt und garantiert noch viel 
mehr unbekannt:
https://gcc.gnu.org/bugzilla/buglist.cgi?bug_status=__open__&no_redirect=1&query_format=specific&order=priority%2Cbug_severity&limit=0

Und an dem arbeitet eine große Community die viele Fehler 
aufdeckt&behebt - dürfte der meistgenutzte Compiler der Welt sein. Bei 
"kleinen" proprietären Compilern sieht das wohl schon anders aus.

von Stefan F. (Gast)


Lesenswert?

> Beim GCC sind derzeit mehr als 10000 bekannt

Wobei das vermutlich größtenteils nur mutmaßliche Bugs sind, die noch 
untersucht und bestätigt oder abgewiesen werden müssen.

von Nop (Gast)


Lesenswert?

Stefan U. schrieb:

> In C ist alles nötige sehr genau definiert. "undefined behaviour"
> provoziert man nur, indem man etwas macht, was nicht vorgesehen ist. Und
> dann bekommt man vom Compiler eine deutliche Warnung.

Nein, die bekommt man nicht. Oder nur manchmal. Wie beispielsweise 
möchtest Du bei undefiniertem Verhalten den Compiler warnen lassen, wenn 
man eine Variable um eine andere Variable shiftet, deren Wert aber erst 
zur Laufzeit bekannt wird?

Um DAS rauszufinden, brauchst Du sehr, sehr aufwendige und damit auch 
teure Tools.

> Es steht Dir frei, den Optimierungs-Grad selbst einzustellen.

C ohne Optimierungen ist ja ziemlich witzlos, weil dann das zentrale 
C-Argument mit der Geschwindigkeit nicht mehr vorhanden ist.

> Das alles sind aber nicht C spezifische Probleme.

Doch, das ist es, weil der Compiler sich beim Optimieren zwar darauf 
verläßt, daß kein undefiniertes Verhalten da ist, aber meistens nicht 
warnt. C enthält schlichtweg zuviel undefiniertes Verhalten, darunter 
auch solches, was man genausogut implementationsabhängig hätte machen 
können.

> Das ist nicht das primäre Ziel der Sprache C.

Genau das ist ja einer der unschönen Punkte an C. Besonders, weil man 
das nichtmal per Debugbuild optional haben kann.

> Hm die ist bei fast allen Programmiersprachen ebenso. Und ich finde sie
> durchaus sinnvoll.

Ich finde sie unsinnig. if (x & MASK == MASK) geht nicht, sondern es muß 
wegen der unsinnigen Priorität if ((x & MASK) == MASK) heißen. Unsinnig 
ist das, weil es so gut wie keinen Fall gibt, in dem man wirklich die 
erstere Variante würde haben wollen.

Daß man beim switch ein break setzen muß, wenn man enden will, anstatt 
ein continue, wenn man in den nächsten case reinlaufen will, ist auch so 
ein Mangel.

> Du musst die alten Funktionen/Libraries ja nicht benutzen.

Das ist keine Widerlegung meines Argumentes, sondern eine Bestätigung.

> Du wirfst da zu viel ein eine Topf. Malloc holt sich Speicher vom OS.
> Also hängt das Verhalten von Malloc direkt von OS ab.

Das ist eben der Kritikpunkt.

von Nop (Gast)


Lesenswert?

Stefan U. schrieb:

> Was die Library angeht: Du musst sie nicht benutzen. Schreibe Dir eine
> eigene!

Achja, übrigens ist schon die dahinterliegende implizite Grundannahme 
vollkommen verkehrt. Man schreibt sich in aller Regel nämlich die 
Codebasis, an der man arbeitet, nicht als Einzelner im stillen 
Kämmerlein from scratch selber.

von Stefan F. (Gast)


Lesenswert?

> C ohne Optimierungen ist ja ziemlich witzlos, weil dann das zentrale
> C-Argument mit der Geschwindigkeit nicht mehr vorhanden ist.

Sage das nicht. Ich habe das mal bei meinen eigenen Programmen 
ausprobiert und war erstaunt, dass der Code nur wenig größer und 
langsamer wurde, als mit Optimierung.

Ich hatte da ein Verhältnis von 1:5 erwartet, aber es war am Ende 
weniger als 1:2.

> if (x & MASK == MASK) geht nicht

Das ist ein schönes Beispiel, um zu erklären, warum du die Rangfolge 
nicht magst. Jetzt verstehe ich dich besser.

>> Du musst die alten Funktionen/Libraries ja nicht benutzen.
> Das ist keine Widerlegung meines Argumentes, sondern eine Bestätigung.

Ok

von S. R. (svenska)


Lesenswert?

Stefan U. schrieb:
> Was die Library angeht: Du musst sie nicht benutzen.
> Schreibe Dir eine eigene!

Den Mangel, dass Arrays bei Übergabe zu Pointern ohne Längeninformation 
zerfallen, kann man damit aber auch nicht lösen. Oder ein paar andere 
Dinge, die im Kern der Sprache verankert sind.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Nop schrieb:
> Torsten R. schrieb:
>
>> was stört Dich den an C, was Du hoffst, in anderen Sprachen zu finden?
>
> Unschön ist die Unmenge an undefined behaviour, besonders weil der
> Compiler dann halt "irgendwas" macht, aber garantiert nichts Nützliches.

Ja, wenn das Dein Hauptkriterium an einer Sprache ist, hast Du 
eingentlich nur 2 Möglichkeiten:

1) (fast) keine Abstraktionen: das wäre dann z.B. Assembler

2) In allen Abstraktionen, definiertes Verhalten:

Du must Dich ja nicht alleine auf die Garantien stützen, die Dir die 
Sprache gibt. Wenn Du andere Garantien haben möchtest oder brauchst, 
dann gibt evtl. einen C-Compiler / Plattform, die das bieten. Undefined 
behaviour verbietet ja nicht, dass es Tools gibt, die Verhalten an der 
Stelle definieren. Der Code wäre dann halt nicht mehr protabel. Unter 
Umständen ist das dann aber das kleinere Übel.

C ist aber halt eine multi-purpose language. Und genau zu definieren, 
wie sich strcpy( 0, 0 ) verhält bedingt halt z.T. teure Prüfungen, der 
derjenige, der das nicht braucht, nicht haben möchte.

von Stefan F. (Gast)


Lesenswert?

Man kann aber Arrays und String durch Objekte ersetzen. Dann sind wir 
allerdings schon bei C++.

Obwohl: Objekt-Orientiert kann man auch in C programmieren. Nur gewinnt 
man damit ebenfalls keinen Schönheitswettbewerb.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nop schrieb:
> Wie beispielsweise möchtest Du bei undefiniertem Verhalten den
> Compiler warnen lassen, wenn man eine Variable um eine andere
> Variable shiftet, deren Wert aber erst zur Laufzeit bekannt wird?
>
> Um DAS rauszufinden, brauchst Du sehr, sehr aufwendige und damit auch
> teure Tools.

3.11 Program Instrumentation Options

GCC supports a number of command-line options that control adding 
run-time instrumentation to the code it normally generates. [...] 
Another class of program instrumentation is adding run-time checking to 
detect programming errors like invalid pointer dereferences or 
out-of-bounds array accesses, as well as deliberately hostile attacks 
such as stack smashing or C++ vtable hijacking. There is also a general 
hook which can be used to implement other forms of tracing or 
function-level instrumentation for debug or program analysis purposes.
1
-fsanitize=address
2
-fsanitize=kernel-address
3
-fsanitize=thread
4
-fsanitize=leak
5
-fsanitize=undefined
6
-fsanitize=shift
7
-fsanitize=shift-exponent
8
-fsanitize=shift-base
9
-fsanitize=integer-divide-by-zero
10
-fsanitize=unreachable
11
-fsanitize=vla-bound
12
-fsanitize=null
13
-fsanitize=return
14
-fsanitize=signed-integer-overflow
15
-fsanitize=bounds
16
-fsanitize=bounds-strict
17
-fsanitize=alignment
18
-fsanitize=object-size
19
-fsanitize=float-divide-by-zero
20
-fsanitize=float-cast-overflow
21
-fsanitize=nonnull-attribute
22
-fsanitize=returns-nonnull-attribute
23
-fsanitize=bool
24
-fsanitize=enum
25
-fsanitize=vptr
26
-fsanitize=pointer-overflow
27
-fsanitize=builtin
28
-fasan-shadow-offset=number
29
-fsanitize-sections=...
30
-fsanitize-recover=
31
-fsanitize-address-use-after-scope
32
-fsanitize-undefined-trap-on-error
33
-fsanitize-coverage=trace-pc
34
-fsanitize-coverage=trace-cmp
35
-fbounds-check
36
-fcheck-pointer-bounds
37
-fchkp-check-incomplete-type
38
-fchkp-narrow-bounds
39
-fchkp-first-field-has-own-bounds
40
-fchkp-flexible-struct-trailing-arrays
41
-fchkp-narrow-to-innermost-array
42
-fchkp-optimize
43
-fchkp-use-fast-string-functions
44
-fchkp-use-nochk-string-functions
45
-fchkp-use-static-bounds
46
-fchkp-use-static-const-bounds
47
-fchkp-treat-zero-dynamic-size-as-infinite
48
-fchkp-check-read
49
-fchkp-check-write
50
-fchkp-store-bounds
51
-fchkp-instrument-calls
52
-fchkp-instrument-marked-only
53
-fchkp-use-wrappers
54
-fcf-protection=
55
-fstack-protector
56
-fstack-protector-all
57
-fstack-protector-strong
58
-fstack-protector-explicit
59
-fstack-check
60
-fstack-clash-protection
61
-fstack-limit-register=reg
62
-fstack-limit-symbol=sym
63
-fstack-limit
64
-fsplit-stack
65
-fvtable-verify=

Immerhin ein Anfang, auch wenn die Warning / Analyse nicht vom Compiler 
kommt sondern qua Instrumentierung zur Laufzeit.

Naturgemäß ist sowas für Cross-Entwicklung schlechter zu nutzen und auch 
schlechter unterstützt als für Host-Entwicklung, aber die Behauptung, 
dass ohne teure [tm] Tools nix ginge, ist wohl etwas grobschlächtig.

Dann sind da noch Tools wie Valgrind oder Mudflap, oder Tools zur 
statischen Analyse.

Gegeben den Fall, dass man Embedded-Entwicklung ernsthaft betreibt, wird 
man den Code sauber in Hardware-Abhängiges und in Hardware-Unabhängiges 
wie Algorithmen und Verwaltungskrempel etc. aufgeteilt haben und 
entsprechend betesten.  Der HW-unabhängige Teil läuft also auch auf 
einem Host mit voller Verfügbarkeit o.g. Instrumenter — wobei die 
Übertragbarkeit der Ergebnisse umso mehr eingeschränkt ist, je weiter 
die Plattformen voneinander abweichen (z.B. sind Ergebnisse für int=32 
gröber als für int=16, und weil int-Promotion nicht portiert werden 
kann).

von Nop (Gast)


Lesenswert?

Torsten R. schrieb:

> 2) In allen Abstraktionen, definiertes Verhalten:

Daß das Performance kostet, ist schon klar. Deswegen würde ich das ja 
auch nur für Debug-Builds haben wollen. Quasi eine Art Pascal-Modus für 
den C-Compiler.

Stefan U. schrieb:
> Obwohl: Objekt-Orientiert kann man auch in C programmieren. Nur gewinnt
> man damit ebenfalls keinen Schönheitswettbewerb.

Zumal die grundlegenden Probleme sich damit auch nicht erledigen. 
Deswegen verwendet man in C++ ja tunlichst keine rohen C-Pointer.

von Nop (Gast)


Lesenswert?

Johann L. schrieb:

> Immerhin ein Anfang, auch wenn die Warning / Analyse nicht vom Compiler
> kommt sondern qua Instrumentierung zur Laufzeit.

Geht aber auch nur unter Linux und hilft nicht besonders weiter, wenn 
man damit Mikrocontroller programmieren will.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Nop schrieb:
> Torsten R. schrieb:
>
> Daß das Performance kostet, ist schon klar. Deswegen würde ich das ja
> auch nur für Debug-Builds haben wollen. Quasi eine Art Pascal-Modus für
> den C-Compiler.

Wie wäre es mit --just-like-java ? ;-)

von Nop (Gast)


Lesenswert?

Torsten R. schrieb:

> Wie wäre es mit --just-like-java ? ;-)

Ein -fno-stupid wäre mir ja schon genug. ^^

von Stefan F. (Gast)


Lesenswert?

> Deswegen würde ich das ja auch nur für Debug-Builds haben wollen.

Kannst du doch: Die Option dazu heisst -O0

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nop schrieb:
> Johann L. schrieb:
>
>> Immerhin ein Anfang, auch wenn die Warning / Analyse nicht vom Compiler
>> kommt sondern qua Instrumentierung zur Laufzeit.
>
> Geht aber auch nur unter Linux und hilft nicht besonders weiter, wenn
> man damit Mikrocontroller programmieren will.

Lies meinen Post einfach zu Ende :-/

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Noch einer: 1 Seite Pascal ~ 1 Zeile C.
Pascal ist so elend viel Tipparbeit ;)

von (prx) A. K. (prx)


Lesenswert?

Joachim D. schrieb:
> Noch einer: 1 Seite Pascal ~ 1 Zeile C.
> Pascal ist so elend viel Tipparbeit ;)

Dann solltest du dir mal APL ansehen. ;-)

von Bernd K. (prof7bit)


Lesenswert?

Programierer schrieb:
> Hallo,
>
> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?
>
> Die allgegenwärtigen libs (in C geschrieben!) sollte man aber noch
> weiter verwenden können.
>
> (Ich habe über die Jahre eine leichte C-Allergie entwickelt, die auch
> bei C++ und ähnlichen auftritt)

Konfuzius sagt: Wenn Du Dich einer Vergewaltigung nicht entziehen kannst 
dann lehne Dich zurück und genieße sie.

Du wirst nicht um C herumkommen. Also mach das beste draus.

von Nop (Gast)


Lesenswert?

Stefan U. schrieb:
>> Deswegen würde ich das ja auch nur für Debug-Builds haben
> wollen.
>
> Kannst du doch: Die Option dazu heisst -O0

Und damit zerfallen dann z.B. Arrays nicht mehr zu Pointern unter 
Verlust der Längeninformation?

Johann L. schrieb:

> Lies meinen Post einfach zu Ende :-/

Habe ich. Ist in der Praxis aber nur begrenzt nützlich. Wenn auch noch 
ein µC-spezifisches OS zum Einsatz kommt, wird der Aufbau eines Mockups 
so richtig spaßig. Die dafür nötige zusätzliche Entwicklungszeit fällt 
übrigens auch nicht kostenlos vom Himmel.

Es bleibt dabei, daß es diese Möglichkeit "gratis" nur dann gibt, wenn 
man sowieso Applikationen für Linux erstellt, was die Sache relativ 
nutzlos macht.

von Nase (Gast)


Lesenswert?

Brille schrieb:
> Ist dein Wissen dazu überhaupt noch aktuell? Oder sind die Bugs
> vielleicht schon längst fehlerbereinigt ..
Ebendas gab ich zu bedenken. Mein Wissen datiert etwa auf Anfang 2017.

Brille schrieb:
> Muss wirklich JEDES Codeschnipsel immer "hoch optimiert" sein? Sind wir
> nicht längst aus dem Zeitalter der "ich muss noch ein paar Bytes mehr
> rausquetschen" Analogie herausgewachsen?
Natürlich.
Nur erzeugt z.B. der GCC selbst auf langweiligster Optimierungsstufe 
etwa um Faktor 5 weniger Code. Bei Mikroe fehl(ten damals) ja selbst 
simpelste Sachen wie Speicherzugriffe zusammenzuziehen.
Ich erinnere mich düster an elendige Wüsten im Assembly aus "lds lds .. 
sts sts" (AVR), nur um ein paar Bits in einer lokalen Variable zu setzen 
(nee...ohne volatile natürlich).

von Bernd K. (prof7bit)


Lesenswert?

Joachim D. schrieb:
> Noch einer: 1 Seite Pascal ~ 1 Zeile C.
> Pascal ist so elend viel Tipparbeit ;)

So extrem ist das nicht. Das meiste macht doch die IDE automatisch auf 
Knopfdruck (Methoden und Interfaces implementieren, etc.) und begin geht 
mir auf ner deutschen Tastatur schneller von der Hand als die unsägliche 
geschweifte Klammer. Unterm Strich beibt da auch nicht viel mehr zu 
schreiben als bei den meisten anderen statisch getypten Syntaxen aus 
dieser Familie auch (C++, Java, C#, etc.).

Und wenn man (wie ich) auch unter Pascal den 1TBS/Kernel-"Klammer"-stil 
pflegt (begin ans Ende der Zeile) kommt auch verkleichbar kompakter Code 
raus.

von iaär (Gast)


Lesenswert?

>was in C so lautet:
>
1
#define NVIC_ISPR     (*((volatile unsigned long *)   (0xE000E200)))
>
>wäre in Pascal etwa so:
>NVIC_ISPR : dword absolute $E000E200;

naja... ist auch ein bisschen vom C Compiler abhängig.
Bei IAR dürfte das gehen - und dann sind wir sogar noch etwas 
übersichtlicher als Pascal.
1
uint32_t NVIC_ISPR @0xE000E200;

von dummschwaetzer (Gast)


Lesenswert?

Stefan U. schrieb:
>> if (x & MASK == MASK) geht nicht

ist doch if(x & MASK), da interessiert doch die Rangfolge zu == 
überhaupt nicht.

von Stefan F. (Gast)


Lesenswert?

>> if (x & MASK == MASK) geht nicht
> ist doch if(x & MASK), da interessiert doch die
> Rangfolge zu == überhaupt nicht.

Doch, denn beabsichtigt war ja das Verhalten von
if ((x & MASK) == MASK)

von Bernd K. (prof7bit)


Lesenswert?

dummschwaetzer schrieb:
> Stefan U. schrieb:
>>> if (x & MASK == MASK) geht nicht
>
> ist doch if(x & MASK), da interessiert doch die Rangfolge zu ==
> überhaupt nicht.

Nein, das ist nicht das selbe.

von dummschwaetzer (Gast)


Lesenswert?

if ((x & MASK) == MASK)
ist für mich gleich
if(x & MASK)
oder wo ist der Unterschied?

von (prx) A. K. (prx)


Lesenswert?

dummschwaetzer schrieb:
> if ((x & MASK) == MASK)
> ist für mich gleich
> if(x & MASK)
> oder wo ist der Unterschied?

Annahme MASK == 0x0F
Oben: Alle Bits müssen gesetzt sein.
Unten: Mindestens ein Bit muss gesetzt sein.

von iaär (Gast)


Lesenswert?

if(x & MASK) ist auch wahr, wenn Du 000001 mit der Maske 00001111 
verUNDest

von Nop (Gast)


Lesenswert?

dummschwaetzer schrieb:
> if ((x & MASK) == MASK)
> ist für mich gleich
> if(x & MASK)
> oder wo ist der Unterschied?

Laß MASK mal mehr als ein Bit gesetzt haben, dann wäre (x & MASK) gleich 
TRUE, auch wenn in x nur ein Tuil der Bits von MASK gesetzt sind.

Außerdem ist (x & MASK == MASK) soviel wie (x & 1), unabhängig vom 
Inhalt von MASK.

von Stefan F. (Gast)


Lesenswert?

> if ((x & MASK) == MASK)
> ist für mich gleich
> if(x & MASK)
> oder wo ist der Unterschied?

Setzen wir konkrete Werte ein:
x=17
MASK=16

((17 & 16) == 16) ist wahr
(17 & 16) ist >0 also auch wahr

Setzen wir andere Werte ein:
x=0
MASK=16

((0 & 16) == 0) ist wahr
(0 & 16) ist 0, also falsch

Jetzt verstanden?

von dummschwaetzer (Gast)


Lesenswert?

Hallo,
((x&MASK)==MASK),
dein Beispiel
(((0 & 16) == 0)
wird also zu
(0 & 16) == 16)
und falsch.klappt alo.
gut, es wahren die mehr als ein Bit, ich verwende dieses Konstrukt nur 
zum Testen eines Bits.

von Rainer S. (rsonline)


Lesenswert?

Nase schrieb:
> Die Compiler würde ich mir aber genau angucken, bevor ich damit
> professionell loslege. Zumindest die AVR-Compiler sind/waren unter aller
> Sau(*), inklusive lächerlichem Optimierer und extrem subtilen Bugs(**).

Funktioniert hier hervorragend im produktiven Einsatz seit mehreren 
Jahren.

In der Tat habe ich einen Bug gefunden, der selten auftritt. Der ist 
mittlerweile behoben und ich werde bei den Credits bei der Compilerinfo 
genannt.

von Stefan F. (Gast)


Lesenswert?

> dein Beispiel
> (((0 & 16) == 0)
> wird also zu
> (0 & 16) == 16)

Oh ja, natürlich du hast Recht.

von Ben W. (ben_w)


Lesenswert?

ich schätze mal Rust wurde schon genannt,
dort gibt es mittlerweile alle Register namen dank der svd2rust tools.

von Vincent H. (vinci)


Lesenswert?

Ben W. schrieb:
> ich schätze mal Rust wurde schon genannt,
> dort gibt es mittlerweile alle Register namen dank der svd2rust tools.

Das Tool ist auch super, nur bringts leider nix wenn die SVD schlichtweg 
unbrauchbar sind. Und zumindest bei ST sind sie das...

von BCPL (Gast)


Lesenswert?

Vincent H. schrieb:

> Das Tool ist auch super, nur bringts leider nix wenn die SVD schlichtweg
> unbrauchbar sind. Und zumindest bei ST sind sie das...

Was genau ist denn unbrauchbar?

AFAIK, werden die .svd Dateien auch von den Debuggern benutzt.

von Olaf (Gast)


Lesenswert?

> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
> die auch mit wenig ram&rom (4kB/32kB) auskommt?

Forth. Damit hast du dann auch ein Alleinstellungmerkmal.

Olaf

von chris (Gast)


Lesenswert?

>Forth. Damit hast du dann auch ein Alleinstellungmerkmal.

Aber nur wenn Du die mindestens 20 verschiedenen Forthsystem ignorierst, 
die es für ARM-Controller gibt ;-)

von Tina (Gast)


Lesenswert?

Ich kann die PAscal wärmstens!! empfehlen.
Von Mikroe.
Wenn man sich dann in Pascal gut zurecht findet, schreibst Du Programme 
auf dem PC gleich auch in PAscal.
Mit Lazarus Freepascal hast Du dann was, wo Du in kürzester Zeit super 
Sachen machen kannst.
Das einzige was da dran komme wäre Visual C++ von MS nur unendlich 
komplexer.
Daher meine dringende Empfehlung Pascal.
Lass Dir keinen Unsinn einreden das PAscal nicht für Bitzugriffe taugt, 
Leute die das behaubten, haben nicht verstanden.
Die vergleichen Pascal aus den 7=/80er Jahren mit dem C von 
heute..sinnvoller wäre es aber Pascal von heute mit C von heute zu 
vergleichen..
Dann würde viele eher Pascal verwenden als in C zu frickeln

von Tina (Gast)


Lesenswert?

dazu muss man sagen, mikroe unterstützt so ziemlich alle gängigen STM32 
Chips und noch einige andere.
Auch das Pascal eignet sich mittlerweile für den produktiven Einsatz.
Viel Kritik die ich hier lese, galt noch vor einigen Jahren..aber die 
Welt dreht sich weiter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tina schrieb:
> Von Mikroe.

Jaja, Thread nicht gelesen …

von Marek F. (marek_f)


Lesenswert?

Nop schrieb:
> Programierer schrieb:
>
>> welche andere Programmiersprachen könnt ihr für ARM cortex M empfehlen,
>> die auch mit wenig ram&rom (4kB/32kB) auskommt?
>
> Free Pascal, weil C-Allergiker oftmals Pascal mögen.

Ich mag C

von Marek F. (marek_f)


Lesenswert?

Tina schrieb:
> Dann würde viele eher Pascal verwenden als in C zu frickeln

In C wird nicht gefrickelt.

ASM dazu was brauchst du mehr?

von Franz F. (franzman)


Lesenswert?

Hat jemand Erfahrung mit micropython?
https://github.com/micropython/micropython

Hab ich jetzt gerade auf der oben verlinkten Wiki Seite entdeckt und 
scheint recht aktiv zu sein.

von Tina (Gast)


Lesenswert?

zu Mikroe..weshalb Thread nicht gelesen.
Hatte gesehen das es bereits erwähnt wurde, aber ganz offensichltich 
nocha uf ganz frühe Versionen bezogen.
Mittlerweile läuft das ganz brauchbar und wir auch im Kommerziellen 
Bereich eingesetzt, wie Lazarus Free Pascal übrigens auch

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tina schrieb:
> ganz offensichltich nocha uf ganz frühe Versionen bezogen.

Ist „Anfang 2017“ wirklich „ganz früh“?

Beitrag "Re: Alternativen zu C, C++ auf ARM cortex M?"

von Nop (Gast)


Lesenswert?

Ist eigentlich das Pascal von Microe kompatibel mit Free Pascal?

von Holm T. (Gast)


Lesenswert?

W.S. schrieb:
> was in C so lautet:
> #define NVIC_ISPR     (*((volatile unsigned long *)   (0xE000E200)))
>
> wäre in Pascal etwa so:
> NVIC_ISPR : dword absolute $E000E200;
> easy, gelle? aber leider eben nicht zu kriegen.
>
> W.S.

Du vergleichst Äppel Mit Kohlrouladen.

Gruß,

Holm

von Holm T. (Gast)


Lesenswert?

Nop schrieb:
> Thomas E. schrieb:
>
>> Und wo ist da das Pascal-Pendant zu "volatile"?
>
> Pascal hat kein volatile.
>
>> In FPC, every statement is basically considered to be a compiler-level
>> memory barrier for accesses to global variables. So within a single
>> statement multiple accesses can be optimised, but that cannot happen not
>> across statements. It's not perfect since it inhibits some optimisation,
>> but on the flip side it's very simple and easy to reason about.
>
> Quelle:
> http://lists.freepascal.org/pipermail/fpc-pascal/2015-December/046057.html

Ist aber sowieso Wurscht da die obere Zeile nur ein Präprozessor Symbol 
definiert, ohne jede Funktionalität dahinter.Das ist nichts weiter als 
#define lehmann 5

..jedes Auftreten von lehmann im folgenden Text wird durch 5 ersetzt. 
Das vergleicht W.W. mit einer Variablendefinition.

Die ganze Sache wird in Pascal ohne volatile recht lustig wenn die 
Variable ohne Wissen des Compilers ihren Wert ändert (memory mapped 
register)..

Gruß,

Holm

von Holm T. (Gast)


Lesenswert?

Tina schrieb:
[..]
> Dann würde viele eher Pascal verwenden als in C zu frickeln

Aha. Pascal verwendet man, in C frickelt man.

Kompetente Auskunft.

Gruß,

Holm

von Nop (Gast)


Lesenswert?

Holm T. schrieb:

> Die ganze Sache wird in Pascal ohne volatile recht lustig wenn die
> Variable ohne Wissen des Compilers ihren Wert ändert (memory mapped
> register)..

Eben nicht, weil zumindest Free Pascal das von sich aus als volatile 
handhabt, wenn ich die genannte Quelle richtig verstehe. Dafür geht die 
Optimierung bei non-volatile halt nicht.

Andere Pascal-Compiler könnten das natürlich anders machen, weil reales 
Pascal mangels brauchbarer Standard-Grundlage schon immer balkanisiert 
war.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Tina schrieb:
> Ich kann die PAscal wärmstens!! empfehlen.
> Von Mikroe.

Der TE hat nach eigener Aussage eine C-Allergie. Da mikroPascal eher ein
mutiertes C als ein echtes Pascal ist (was man durchaus auch positiv
sehen kann), wird er vermutlich auch darauf allergisch reagieren.

Nop schrieb:
> Eben nicht, weil zumindest Free Pascal das von sich aus als volatile
> handhabt, wenn ich die genannte Quelle richtig verstehe. Dafür geht die
> Optimierung bei non-volatile halt nicht.
>
> Andere Pascal-Compiler könnten das natürlich anders machen, weil reales
> Pascal mangels brauchbarer Standard-Grundlage schon immer balkanisiert
> war.

Das volatile-Qualifier ist einer der Punkte, wo mikroPascal etwas
Sinnvolles von C geerbt hat.

von Vincent H. (vinci)


Lesenswert?

BCPL schrieb:
> Vincent H. schrieb:
>
>> Das Tool ist auch super, nur bringts leider nix wenn die SVD schlichtweg
>> unbrauchbar sind. Und zumindest bei ST sind sie das...
>
> Was genau ist denn unbrauchbar?
>
> AFAIK, werden die .svd Dateien auch von den Debuggern benutzt.

Teilweise fehlende/falsche Bits, teilweise selbst zwischen 2 sehr nah 
verwandten Derivaten komplett unterschiedliche Namensgebung (z.b. 
ADC_Common vs. ADC123_Common, etc.), von anderen Familien braucht man da 
gar nicht erst reden.

Teilweise weit hinterher mit der Verfügbarkeit, zumindest verglichen zu 
den echten Headern, die wohl intern bei ST auch mit irgendeinem Tool 
erzeugt werden...

usw. usf.

Prinzipiell wären SVDs eine tolle Sache, aber nicht wenn man sie nicht 
ordnungsgemäß pflegt. :(

von Nop (Gast)


Lesenswert?

Yalu X. schrieb:

> Das volatile-Qualifier ist einer der Punkte, wo mikroPascal etwas
> Sinnvolles von C geerbt hat.

Ist aber auch wieder typische Pascal-Balkanisierung: je nach Compiler 
sind ungekennzeichnete globale Variablen mal volatile und mal nicht. Das 
passiert halt, wenn's keinen praxistauglichen Standard gibt.

von Bernd K. (prof7bit)


Lesenswert?

Holm T. schrieb:
> Ist aber sowieso Wurscht da die obere Zeile nur ein Präprozessor Symbol
> definiert, ohne jede Funktionalität dahinter.

Sobald man das Prärozessorsymbol mit seinem darin enthaltenen volatile 
in seinen Code einbaut wird es genauso wirksam als hätte man es direkt 
selbst dort hingeschrieben.

> Das ist nichts weiter als
> #define lehmann 5

weder "lehmann" noch "5" kann ich im verlinkten Post finden.

> Die ganze Sache wird in Pascal ohne volatile recht lustig

Nein, denn wenn Du das von Dir zitierte Post auch gelesen hättest dann 
hättest Du gesehen daß in FPC jeder Strichpunkt eine Speicherbarriere 
ist, bzw der Compiler enthält schlichtweg keine Optimierungen die über 
solche Grenzen hinweg optimieren. Also ist praktisch von Haus aus alles 
immer volatile. Solange das so bleibt braucht man sich auch keine 
Gedanken um diesen gesamten Themenkomplex machen. Der Preis den man 
zahlt sind massiv schlechtere Compileroptimierungen.

Das wird wahrscheinlich erst wieder interessant wenn irgendwann mal FPC 
wie seit Jahren geplant auf LLVM als Backend umsteigt, selbiges könnte 
wahrscheinlich potentiell bedeutend besser optimieren als der bisherige 
FPC und Nutzen aus nicht-volatilen Variablen ziehen, vielleicht wird es 
dann eingeführt.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Der TE hat nach eigener Aussage eine C-Allergie. Da mikroPascal eher ein
> mutiertes C als ein echtes Pascal ist (was man durchaus auch positiv
> sehen kann), wird er vermutlich auch darauf allergisch reagieren.

Zumindest besteht eine deutliche Chance einer solchen Kreuzallergie.

: Bearbeitet durch User
von Holm T. (Gast)


Lesenswert?

Bernd K. schrieb:
> Holm T. schrieb:
>> Ist aber sowieso Wurscht da die obere Zeile nur ein Präprozessor Symbol
>> definiert, ohne jede Funktionalität dahinter.
>
> Sobald man das Prärozessorsymbol mit seinem darin enthaltenen volatile
> in seinen Code einbaut wird es genauso wirksam als hätte man es direkt
> selbst dort hingeschrieben.
>
Loriot: Ach!?

Du definierst also Interrupt Service Routinen immer im cpp und nicht im 
Compiler oder Assembler?

>> Das ist nichts weiter als
>> #define lehmann 5
>
> weder "lehmann" noch "5" kann ich im verlinkten Post finden.

Wirklich nicht? Tatsache! Bernd K. aber auch nicht.
>
>> Die ganze Sache wird in Pascal ohne volatile recht lustig
>
> Nein, denn wenn Du das von Dir zitierte Post auch gelesen hättest dann
> hättest Du gesehen daß in FPC jeder Strichpunkt eine Speicherbarriere
> ist, bzw der Compiler enthält schlichtweg keine Optimierungen die über
> solche Grenzen hinweg optimieren. Also ist praktisch von Haus aus alles
> immer volatile. Solange das so bleibt braucht man sich auch keine
> Gedanken um diesen gesamten Themenkomplex machen. Der Preis den man
> zahlt sind massiv schlechtere Compileroptimierungen.
>
Nein! Doch! Oh..

> Das wird wahrscheinlich erst wieder interessant wenn irgendwann mal FPC
> wie seit Jahren geplant auf LLVM als Backend umsteigt, selbiges könnte
> wahrscheinlich potentiell bedeutend besser optimieren als der bisherige
> FPC und Nutzen aus nicht-volatilen Variablen ziehen, vielleicht wird es
> dann eingeführt.

Du bekommst von mir einen grünen Gummipunkt zum Sammeln. Hast Du Dir 
echt verdient.

Gruß,

Holm

von W.S. (Gast)


Lesenswert?

Bernd K. schrieb:
> Nein, denn wenn Du das von Dir zitierte Post auch gelesen hättest dann
> hättest Du gesehen daß in FPC jeder Strichpunkt eine Speicherbarriere
> ist, bzw der Compiler enthält schlichtweg keine Optimierungen die über
> solche Grenzen hinweg optimieren. Also ist praktisch von Haus aus alles
> immer volatile. Solange das so bleibt braucht man sich auch keine
> Gedanken um diesen gesamten Themenkomplex machen. Der Preis den man
> zahlt sind massiv schlechtere Compileroptimierungen.

Vorsicht bei derartigen Schlußfolgerungen, wenn man so C-orientiert 
argumentiert wie du grad eben.

Normalerweise gilt bei Pascal das "immer volatile" nur für Variablen, 
die eine Prozedur oder Funktion nicht unter ihrer vollständigen 
Kontrolle hat.

Das ist aber ne subtile Sache.

Erstens sind lokale Variablen einer Prozedur oder Funktion nicht 
volatile, es sei denn, sie werden von lokalen Prozeduren/Funktionen 
verwendet. (ja, dieses Konzept gibt es in Pascal).

Zweitens sind unit-interne globale Variablen nur dann volatile, wenn sie 
entweder im Interface veröffentlicht sind oder innerhalb des Units von 
mehreren Instanzen verwendet werden, so daß eine Instanz eben nicht 
davon ausgehen kann, daß sie den alleinigen Zugriff darauf hat.

Und ein wirklich auf µC als Zielplattform portiertes Pascal müßte das 
"absolute" automatisch als volatile behandeln, das ist ja wohl klar.

Nun ja, kommen wir noch kurz zu Mikroe und deren Pascal: Da ist nach wie 
vor nur eine beschränkte Auswahl an Zielplattformen möglich - und als 
Anwender kann man diese nicht erweitern. Genau das ist ein 
Disqualifizierungsmerkmal gegenüber den üblichen C-Compilern jenseitsvon 
Mikroe. Ich hab grad mal geschaut: einige Freescale MK22xx, dazu viele 
STM32, Texas/Stellaris - aber ansonsten weder LPC noch Nuvotons usw.

W.S.

von Tina (Gast)


Lesenswert?

wowzu auch...das ist eben genau das Problem von diesem Opensource 
Gedanken..alles muss frei und toll und für alles sein.Schlussendlich ist 
alles ein wildes Gebastel.
Wir sehen alle wie toll das bei linux klappt...
Bei Mirko e.
Download.
Starten..
Hellow World tippen, übertragen ..läuft!
Hallo world über Uart tippen..übetragen ..läuft..

Das gleiche bei Freepascal..download..Tippen..läuft....

In C geht das höchstens mit MS Visual C++

Mehr will ich damit nicht sagen.
Und Sowohl Freepascal als auch mikroe werden in kommerziellen Produkten 
eingesetzt.
Und diese Gejammer dieses und jenes ginge nicht..so ein Quatsch..im 
Alltag spielt das für 99,9% überhaupt keine Rolle
Und sicher ginge auch Python..hier kenne ich mich aber nicht gut genug 
mit aus, als das ich das jetzt vergleichen könnte..was da mehr doer 
weniger Vorteile hätte im Vergleich zu Pascal.
Lange Rede kein Sinn...teste das doch einfach mal, schau die einfache 
Beispiele an und entscheide selbst.
Ich fände es aber super, wenn Du das Ergebnis hier schreiben würdest, 
egal wie es ausgefallen ist.

Beitrag #5210162 wurde vom Autor gelöscht.
von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Zweitens sind unit-interne globale Variablen nur dann volatile, wenn sie
> entweder im Interface veröffentlicht sind oder innerhalb des Units von
> mehreren Instanzen verwendet werden, so daß eine Instanz eben nicht
> davon ausgehen kann, daß sie den alleinigen Zugriff darauf hat.

Es gibt nicht nur I/O-Ports.

Wie stellt sich das bei Interrupt-Handlern dar? Ohne das Wissen eines 
Compilers, welche der nur innerhalb der Unit oder Instanz verwendeten 
Variablen auch von Handlern genutzt werden, wird es dann doch etwas 
schwierig, oder? Ebenso Multithreading als Erweiterung dieses Prinzips.

Das ist doch im Grunde genau das gleiche Problem. Auch in C wird 
"volatile" nur dort erforderlich, wo der Compiler nicht selber weiss 
worum es geht. Wenn ein non-C Compiler Unit- oder Instanz-lokale 
Variablen nicht optimieren darf, weil mehr dahinter ist als die für ihn 
sichtbare Reihenfolge der Codeausführung, dann muss man ihm das sagen. 
Man kann sich dann nur darüber streiten, in welcher Form man das macht. 
Weiss ein Compiler, dass eine Funktion ein Handler ist, und gibt es 
keine Pointer, dann geht es ohne "volatile", weil er es aus dem Code 
ableiten kann. Andernfalls sind wieder alle Wetten offen.

Mit der erwähnten Beschränkung auf Optimierung nur innerhalb eines 
Statements ist man natürlich auf der sicheren Seite. Aber wenn man 
darüber hinaus will, muss man sich schon Gedanken um Interrupts und 
Multithreading machen. Das Ergebnis muss nicht dem "volatile" in C 
entsprechen, das geht auch anders. Aber irgendwas wird nötig.

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


Lesenswert?

Tina schrieb:
> Mehr will ich damit nicht sagen.

Ist auch besser so, ehrlich.  Das vermeidet, dass du dich hier weiter
mit ausgesprochener „Sachkenntnis“ blamierst.

von (prx) A. K. (prx)


Lesenswert?

Die C Compiler der 70er und frühen 80er arbeiten ungefähr nach dem 
erwähnten Muster, Optimierungen mit Folgen für Zugriffe auf Variablen 
allenfalls innerhalb von Statements durchzuführen.

Die Mainframes waren schon wesentlich weiter, aber die hatten auch die 
Kapazitäten dazu (dortige Erfahrungen führten zur RISC Philosophie). Ein 
Compiler, der ohne allzu viele Overlays in den 64KB grossen logischen 
Adressraums einer PDP-11 passen und dafür keine 12 Passes verbraten 
soll, der ist halt begrenzt.

Es war der Druck neuer ernsthaft optimierender C Compiler auf 32-Bit 
Maschinen, der "volatile" überhaupt erst erforderlich machte.

> wie seit Jahren geplant auf LLVM als Backend umsteigt, selbiges könnte
> wahrscheinlich potentiell bedeutend besser optimieren als der bisherige
> FPC

Eine rigide Beschränkung der Optimierung kann Sinn ergeben. Es gibt 
Umgebungen, in denen Code grundsätzlich nur unoptimiert genutzt wird, 
weils sonst einfach zu gefährlich ist. Lieber mehr Bums in Hardware als 
ein Bums gegen den Baum. Mit der Vorgabe keiner Statement-übergreifender 
Optimierung landet man ähnlich. Was man nicht falsch machen kann, das 
macht man auch nicht falsch.

Ob es dann allerdings überhaupt Sinn ergibt, hochkomplexe Compiler wie 
GCC oder LLVM als Grundlage zu nehmen, möchte ich in Frage stellen. Wenn 
Zuverlässigkeit höchste Priorität hat, dürfte es besser sein, kleine 
übersichtliche Compiler zu verwenden, die Statements ziemlich direkt in 
Code umsetzen. Statt sich mit zigmal grösseren Compilern abzukämpfen, in 
denen ein grosser Teil des Quellcodes überhaupt nicht genutzt wird. Denn 
mit jeder geänderten Zeile im Compiler geht das Test- und 
Zertifizierung-Gedöns erneut los, selbst wenn diese Zeile überhaupt 
nicht zum tragen kommt.

von W.S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Ist auch besser so, ehrlich.

Nee, laß mal. Für das, was die Leute von Mikroe vorgesehen haben, 
funktioniert es wohl. Aber das ist eben auch zugleich die Beschränkung. 
Wenn sich jeder seine Entsprechung zu "meinchip.h" selber schreiben 
könnte (Konjunktiv, kein MUSS), dann wäre das der Verbreitung extrem 
nützlich gewesen. Ist aber nicht, wohl aus Firmenpolitik, also war's 
das.

W.S.

von Nop (Gast)


Lesenswert?

A. K. schrieb:

> mit jeder geänderten Zeile im Compiler geht das Test- und
> Zertifizierung-Gedöns erneut los, selbst wenn diese Zeile überhaupt
> nicht zum tragen kommt.

Ich hatte schon ein solches GCC-Update, bei dem der Test dann sehr 
schnell ging - das erzeugt Hexfile war nämlich dasselbe wie vorher.

von W.S. (Gast)


Lesenswert?

A. K. schrieb:
> Es gibt nicht nur I/O-Ports.
>
> Wie stellt sich das bei Interrupt-Handlern dar?

A. K. schrieb:
> Ebenso Multithreading als Erweiterung dieses Prinzips.

Hast du es denn nicht gelesen, was ich geschrieben habe? Bei 
Interrupthandlern sieht das ganz genauso aus wie bei Threadfunktionen am 
PC.

Meine Delphi-Programme benutzen schon seit ewig Threads und das 
funktioniert auch seit ewig, ohne daß dafür dedizierte Pendants zu 
"volatile" erforderlich wären. Die Regeln dazu hab ich doch umrissen.

Bei C ist das erklärlicherweise schwieriger, weil es dort vieles nicht 
gibt und deshalb in erheblichem Maße mit Zeigern und Casts gearbeitet 
werden muß.

Und mal ganz abgesehen davon..
..schau dir bloß mal an, wie all die STM32-Jünger heutzutage ihre 
Controller programmieren: Da werden XYZ_InitStruct's bis zum Bersten 
gefüllt und ein Stück Libfunktion aufgerufen, wo doch ein simples 
Beschreiben der HW-Register es um Längen effizienter getan hätte. 
Glaubst du wirklich, daß bei solchem Programmierstil ein noch so hoch 
optimierender C-Compiler irgendwas ausrichten kann? Ich nicht.

W.S.

von Tina (Gast)


Lesenswert?

"Ist auch besser so, ehrlich.  Das vermeidet, dass du dich hier weiter
mit ausgesprochener „Sachkenntnis“ blamierst."#

Na versucht da wieder ein Moderator Unruhe zu stiften?....
Sorry, aber solch Kommentare sollte man sich als Mod klemmen

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> Ich hatte schon ein solches GCC-Update, bei dem der Test dann sehr
> schnell ging - das erzeugt Hexfile war nämlich dasselbe wie vorher.

Das hilft dir nicht wirklich. Denn das besagt nicht, dass es bei einer 
Änderung in deinem Programm immer noch neutral bleibt.

Wenn dann auch noch die verwendete Version des Compiler selbst Teil 
einer restriktiven Vorgabe ist, man also nicht einfach den Update der 
IDE ziehen und mal eben das Projekt neu übersetzen darf, dann dürften 
bekannte Bugs des Compilers, um die man herum programmiert, typischer 
sein als neue Versionen des Compilers mit Ausicht auf neue unbekannte 
Bugs.

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> ..schau dir bloß mal an, wie all die STM32-Jünger heutzutage ihre
> Controller programmieren: Da werden XYZ_InitStruct's bis zum Bersten
> gefüllt und ein Stück Libfunktion aufgerufen, wo doch ein simples
> Beschreiben der HW-Register es um Längen effizienter getan hätte.

Hast denn nicht gelesen, was ich schon vor langer Zeit geschrieben habe? 
Meine Rede seit Jahren. ;-)

Effizienz ist aber weniger der Punkt, meistens jedenfalls, wenns dadurch 
immerhin einfacher und übersichtlicher würde. Was es schon aufgrund der 
umständlichen struct-Technik nicht ist. Unschön finde ich auch, dass 
dabei eine gut dokumentierte Hardware durch eine mässig bis schlecht 
dokumentierte Library ersetzt wird. Und man sich spätestens beim 
Debugging sowieso mit der Auswirkung auf die Hardware befassen muss, 
also um dessen Doku sowieso nicht herum kommt.

> Hast du es denn nicht gelesen, was ich geschrieben habe?

Wenn es in dem betreffenden Beitrag stand, dann habe ich es darin nicht 
gefunden. Und im Rest vom Thread auch nicht. Ich bin konkret weder mit 
Delphi noch sonst einem halbwegs aktuellen Pascal näher vertraut, 
weshalb ich deren Konzepte zur Kennzeichnung oder Vermeidung 
nebenläufigen Zugriffs nicht kenne. Genau die würden mich ja 
interessieren.

: Bearbeitet durch User
Beitrag #5210271 wurde vom Autor gelöscht.
von Feldstecher (Gast)


Lesenswert?

A. K. schrieb:
> Wenn es in dem betreffenden Beitrag stand, dann habe ich es darin nicht
> gefunden. Und im Rest vom Thread auch nicht.

Mein Verstaendnis von der Sache: Nur lokale Variablen werden optimiert, 
globale Variablen sind implizit volatil (allerdings nur im Rahmen eines 
Statements). Welche Variablen genau unter lokal und global einsortiert 
werden, weiss ich aber auch nicht.

Ein Interrupt greift auf Hardwareregister zu, diese sind global (= 
volatile). Werte werden in Puffervariablen geschrieben, diese sind 
global (=volatile).

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Glaubst du wirklich, daß bei solchem Programmierstil ein noch so hoch
> optimierender C-Compiler irgendwas ausrichten kann? Ich nicht.
Das hat nix mit Glauben zu tun, das ist gar kein Problem. Gute Compiler 
wie der GCC können noch ganz andere Sachen optimieren, mit mehreren 
verschachtelten temporären Objekten, per templates generierten 
Algorithmen usw. Im konkreten Falle der ST HAL müsste man dazu aber die 
Optimierung erstmal erlauben, indem die Funktionen als "inline" 
markiert, was ST natürlich nicht getan hat. Schlau wäre es zudem, wo 
möglich die structs zu initialisieren und als constexpr zu markieren 
anstelle von nachträglichen Zuweisungen, sodass sie im Flash landen. 
Wird die entsprechende HAL-Funktion mehrfach genutzt, spart man so 
durchaus Flash gegenüber direkten Register-Zugriffen.

Tina schrieb:
> Hellow World tippen, übertragen ..läuft!
> Hallo world über Uart tippen..übetragen ..läuft..
Schön, ein System was die schnelle Implementierung von Hello World 
ermöglicht! Das kann Arduino (C++) auch. Möchte man mehr Freiheiten für 
komplexere Aufgaben, freut man sich über flexiblere Systeme, die dann 
natürlich schwieriger zu handhaben sind.

A. K. schrieb:
> Aber wenn man
> darüber hinaus will, muss man sich schon Gedanken um Interrupts und
> Multithreading machen. Das Ergebnis muss nicht dem "volatile" in C
> entsprechen, das geht auch anders. Aber irgendwas wird nöti
Bei Multithreading ist aber volatile auch ungeeignet, schon alleine weil 
nicht-wegoptimierte Zugriffe noch lange kein "konsistentes" Verhalten 
bei Multiprozessor-Systemen garantieren. Dort nutzt man atomics, Mutexe 
usw.
Beispiel:
1
volatile int a = 0, b = 0;
2
void thread1(void) {
3
  a = 1;
4
  b = 2;
5
}
6
void thread2(void) {
7
  printf ("%d,", b);
8
  printf ("%d\n", a);
9
}
Die Ausgabe kann z.B. "2, 0" sein, trotz volatile. Hier brauchts nicht 
nur Optimierungs-Barrieren, sondern auch Speicher-Barrieren, wie sie von 
atomics geboten werden. Vielleicht kann jemand was dazu sagen, wie 
Pascal das handhabt?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Das hat nix mit Glauben zu tun, das ist gar kein Problem.

In diesem Falle habe ich da schon meine Zweifel.  Da werden Bits in
IO-Register gesetzt (die sind "volatile"), die da schon so drin stehen,
weil man ja diese structs immer komplett befüllen muss als Nutzer, und
die Bibliotheksfunktion sie dann auch komplett in die Hardware
reinwirft.

Hat allerdings nichts mit C oder Alternativen dazu zu tun. :-)

von Nop (Gast)


Lesenswert?

W.S. schrieb:

> Bei C ist das erklärlicherweise schwieriger, weil es dort vieles nicht
> gibt und deshalb in erheblichem Maße mit Zeigern und Casts gearbeitet
> werden muß.

Das ist falsch, denn in C hat volatile weder mit Zeigern noch mit Casts 
etwas zu tun. Es ist in C drin, weil C als Sprache zur 
Systemprogrammierung konzipiert und dann auch eingesetzt worden ist. 
Sobald man den ersten RX/TX-Interrupt hat, wird offensichtlich, daß man 
das braucht.

Pascal hat das nicht, weil es als nutzlose Spielzeugsprache aus dem 
Elfenbeinturm ISO-standardisiert worden ist. In der Folge hat jeder 
Compiler-Hersteller sein eigenes Süppchen kochen müssen, um daraus etwas 
praktisch Brauchbares zu machen.

von (prx) A. K. (prx)


Lesenswert?

Feldstecher schrieb:
> Mein Verstaendnis von der Sache: Nur lokale Variablen werden optimiert,
> globale Variablen sind implizit volatil (allerdings nur im Rahmen eines
> Statements).

So gehts natürlich ohne Kennzeichnung, wie ich schon schrieb. Ist aber 
eben auch recht restriktiv hinsichtlich Optimierung. Im Kontext von 
Controllern kann das ein akzeptabler Kompromiss sein.

Interessant sind Variablen, die nur innerhalb des Moduls (oder Unit, wie 
immer das heisst) bekannt sind, aber ausserhalb der 
Funktionen/Prozeduren. Wenn du diese in deinen Begriff "global" 
einschliesst, dann gibts keine Probleme.

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> Pascal hat das nicht, weil es als nutzlose Spielzeugsprache aus dem
> Elfenbeinturm ISO-standardisiert worden ist. In der Folge hat jeder
> Compiler-Hersteller sein eigenes Süppchen kochen müssen, um daraus etwas
> praktisch Brauchbares zu machen.

Dass es hier nicht um das Wirth'sche Pascal der 70er geht ist 
offensichtlich. Wenn man plattformübergreifend programmiert ist das 
natürlich ein Kriterium, man ist mit Pascal-Deriviaten etwas festgelegt. 
Aber das muss im Controller-Umfeld nicht unbedingt ein grosses Problem 
sein.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Im konkreten Falle der ST HAL müsste man dazu aber die
> Optimierung erstmal erlauben, indem die Funktionen als "inline"
> markiert

Nein. "inline" ist lediglich ein unverbindlicher Vorschlag an den 
Compiler, der aber gemäß der as-if-Philosophie mit und ohne inline 
inlinen kann oder auch nicht.

> was ST natürlich nicht getan hat. Schlau wäre es zudem, wo
> möglich die structs zu initialisieren und als constexpr zu markieren

In C?!

> Die Ausgabe kann z.B. "2, 0" sein, trotz volatile. Hier brauchts nicht
> nur Optimierungs-Barrieren, sondern auch Speicher-Barrieren

Die sind natürlich hardware-spezifisch, aber volatile ist die halbe 
Miete.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Nein. "inline" ist lediglich ein unverbindlicher Vorschlag an den
> Compiler, der aber gemäß der as-if-Philosophie mit und ohne inline
> inlinen kann oder auch nicht.
Korrekt. Aber beim inlinen hat der Compiler viel mehr Möglichkeiten zur 
Optimierung. Optimieren ist ja auch nicht vom Standard vorgeschrieben.

Nop schrieb:
> In C?!
Das ist natürlich C++. "static const" hilft aber auch in C.

Nop schrieb:
> Die sind natürlich hardware-spezifisch, aber volatile ist die halbe
> Miete.
Was bringt die halbe Miete, wenn sie nicht funktioniert? Man nutzt 
einfach atomics wie sie vom Standard vorgeschrieben sind und kein 
volatile, und es funktioniert. volatile braucht man bei normalen 
Programmen mit klassischem Multithreading nie, das ist nur für 
Low-Level-Programmierung mit Interrupts und IO-Registern.

von mh (Gast)


Lesenswert?

A. K. schrieb:
> Es gibt nicht nur I/O-Ports.

In C ist volatile nur für I/O Zugriffe relevant, oder? Volatile 
verhindert kein reordering, synchronisiert nicht und garantiert keine 
atomaren Zugriffe.

Wie sieht das bei Free Pascal aus? Gibt es da so etwas wie _Atomic(Type) 
(C) und atomic<Type> (C++), oder werden alle Zugriffe auf "globale" 
Objekte automatisch voll synchronisiert (barrier,release/acquire, ...), 
oder muss man alles selbst synchronisieren?

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> Sobald man den ersten RX/TX-Interrupt hat, wird offensichtlich, daß man
> das braucht.

In C ja. Aber es sind auch andere Konzepte vorstellbar.

Denk dir eine Sprache, mit ein paar Eigenschaften:
- Es gibt zumindest in Handlern keine Pointer.
- Ein Handler nutzt nur Variablen aus dem Modul, in dem er definiert 
ist.
- Ein Handler wird entsprechend gekennzeichnet.
Dann hat der Compiler den vollen Überblick darüber, welche Variablen auf 
welche Weise nebenläufig sind, ohne dass man die extra kennzeichnen 
müsste. Nämlich nur die in Handlern. Und er könnte dann sogar besser 
optimieren als C, beispielsweise weil er mit einer Variable, die im 
Hauptkontext geschrieben und im Handler gelesen wird, anders umgehen 
kann als umgekehrt.

Multithreading wäre dann ein eigenes Thema.

von Nop (Gast)


Lesenswert?

A. K. schrieb:

> Dass es hier nicht um das Wirth'sche Pascal der 70er geht ist
> offensichtlich.

Schon, aber dieser Unsinn ist standardisiert worden. Eine Konsequenz 
ist, daß eventuelle Änderungen stets abwärtskompatibel sein müssen, weil 
man nicht einfach wie in C sagen kann, nach welchem Standard man denn 
compilieren will. Gibt ja keinen brauchbaren.

> Wenn man plattformübergreifend programmiert ist das
> natürlich ein Kriterium, man ist mit Pascal-Derivaten etwas festgelegt.

Vor allem wird es lästig, wenn man z.B. Mockups erstellen will. Dann ist 
man direkt auf Compiler begrenzt, die auf PC und dem Controller 
verfügbar sind. Effektiv also auf FPC. Für Hobby OK, aber keine Firma 
würde sich auf etwas einlassen, wo man im Ernstfall mit Glück in 
irgendeinem Forum nachhaken kann.

> Aber das muss im Controller-Umfeld nicht unbedingt ein grosses Problem
> sein.

Ist es aber. Da es keine Standards gibt, sondern nur proprietäres 
Gefrickel (und das schon weit vor Turbo-Pascal), finden 
Sprachdiskussionen nicht herstellerübergreifend statt wie bei C. Die 
Folge ist, daß jeder irgendwie erweitert und man überhaupt keine 
referenzierbare Baseline bekommt. Den Vendor-Lockin gibt's natürlich 
gratis dazu.

Mit C muß ich mir keine Gedanken machen, was für einen Compiler und 
Hersteller ich da gerade habe, denn da das standardisiert ist, verhält 
es sich überall gleich. Stellenweise gleich krank, aber immerhin.

Dennoch sehe ich Pascal als Lehrsprache im Vorteil gegenüber C, schon 
weil das strikte Typensystem den Anfänger von vornherein sensibilisiert. 
Zwei/Drei-Sterneprogrammierung braucht ein Anfänger eh nicht.

von Nop (Gast)


Lesenswert?

mh schrieb:

> In C ist volatile nur für I/O Zugriffe relevant, oder?

Jein. Man nimmt das auch, wenn Interrupts einem Sachen in einen Buffer 
schaufeln, den man aus der Applikation lesen will - und umgedreht. Also 
nicht nur direkt für die IO-Register-Zugriffe.

von Dr. Sommer (Gast)


Angehängte Dateien:

Lesenswert?

Jörg W. schrieb:
> In diesem Falle habe ich da schon meine Zweifel.
Sie sind aber unangebracht. Ich verstehe nicht ganz was du meinst, habe 
es aber ausprobiert:
Die angehängte Datei ist eine Zusammenstellung der Funktion und 
Definitionen zur Initialisierung eines GPIO-Pins in der HAL. Die 
Funktion ist mit always_inline markiert. Das sieht dann ziemlich schlimm 
aus und die Funktion ist sehr lang, aber der GCC macht daraus bei -O3:
1
00000000 <test>:
2
   0:  4a03        ldr  r2, [pc, #12]  ; (10 <test+0x10>)
3
   2:  6813        ldr  r3, [r2, #0]
4
   4:  f023 030f   bic.w  r3, r3, #15
5
   8:  f043 0303   orr.w  r3, r3, #3
6
   c:  6013        str  r3, [r2, #0]
7
   e:  4770        bx  lr
8
  10:  40010800   .word  0x40010800
Besser geht's m.W. nicht. Ob Pascal-Compiler, oder proprietäre Compiler 
wie der ARMCC so gut sind, bliebe noch zu erforschen...

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Was bringt die halbe Miete, wenn sie nicht funktioniert? Man nutzt
> einfach atomics wie sie vom Standard vorgeschrieben sind

Atomics in C? Nach welchem Standard?

Ansonsten kann man ohne weiteres volatile kombinieren mit einem Macro, 
das einem einen hardwaremäßigen Memsync gibt, und schon hat man, was man 
braucht. Ich hab sowas auch schon gemacht, weil das zwar in gewisser 
Weise ein dirty hack ist, dafür aber portabel unter allen 
Betriebssystemen funktioniert. Sollte man halt nicht gerade so einbauen, 
daß es einem die Performance ruiniert.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Atomics in C? Nach welchem Standard?
C11.

Nop schrieb:
> Ansonsten kann man ohne weiteres volatile kombinieren mit einem Macro,
> das einem einen hardwaremäßigen Memsync gibt, und schon hat man, was man
> braucht.
Über fiese Hacks und Inline-Assembler brauchen wir wohl nicht zu 
diskutieren...

von mh (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Beispiel:
1
volatile int a = 0, b = 0;
2
void thread1(void) {
3
  a = 1;
4
  b = 2;
5
}
6
void thread2(void) {
7
  printf ("%d,", b);
8
  printf ("%d\n", a);
9
}
> Die Ausgabe kann z.B. "2, 0" sein, trotz volatile.

Das ist leider so nicht ganz richtig. Die schreibenden Zugriffe auf a 
und b in thread1 dürfen nicht vertauscht werden weil a und b volatile 
sind.

von (prx) A. K. (prx)


Lesenswert?

mh schrieb:
> In C ist volatile nur für I/O Zugriffe relevant, oder?

Nein, es ist auch für Interrupts und Multithreading relevant. Atomarer 
Zugriff ist zwar ein eigenes Thema, aber wenn aufgrund entsprechender 
Massnahmen gesichert ist, dass kein nicht-atomarer Zugriff unterbrochen 
wird, muss trotzdem sichergestellt werden, dass ein Zugriff überhaupt 
stattfindet.

Der Klassiker hierfür ist:
1
bool flag;
2
3
void handler(void) 
4
{ 
5
  flag = true; 
6
}
7
8
void run(void)
9
{
10
  .. egal was, aber lass "flag" in Ruhe ..
11
}
12
13
void f(void)
14
{
15
  for (;;) {
16
    if (flag) {
17
       run();
18
       flag = false;
19
    }
20
  }
21
}

Ohne "volatile" bei "flag" wird ein optimierender Compiler in f() nicht 
jedesmal in der Schleife auf "flag" zugreifen, sondern genau 1x am 
Anfang und von der Änderung nichts mitkriegen.

von Dr. Sommer (Gast)


Lesenswert?

mh schrieb:
> Die schreibenden Zugriffe auf a
> und b in thread1 dürfen nicht vertauscht werden weil a und b volatile
> sind.
Vom Compiler nicht. Der Prozessor weiß davon nix und kann die anordnen 
wie er lustig ist.

von Dr. Sommer (Gast)


Lesenswert?

Hier noch eine Quelle dazu:
https://stackoverflow.com/a/4558031
"Short & quick answer: volatile is (nearly) useless for 
platform-agnostic, multithreaded application programming. It does not 
provide any synchronization, it does not create memory fences, nor does 
it ensure the order of execution of operations. It does not make 
operations atomic. It does not make your code magically thread safe. 
volatile may be the single-most misunderstood facility in all of C++."

von mh (Gast)


Lesenswert?

Nop schrieb:
> mh schrieb:
>
>> In C ist volatile nur für I/O Zugriffe relevant, oder?
>
> Jein. Man nimmt das auch, wenn Interrupts einem Sachen in einen Buffer
> schaufeln, den man aus der Applikation lesen will - und umgedreht. Also
> nicht nur direkt für die IO-Register-Zugriffe.

In dem Fall muss der Zugriff aber auch atomar sein. Die Zugriffe dürfen 
also nicht unterbrechbar sein und dürfen nicht umgeordnet werden.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Nop schrieb:
>> Atomics in C? Nach welchem Standard?
> C11.

Ah, gut zu wissen, danke.

> Über fiese Hacks und Inline-Assembler brauchen wir wohl nicht zu
> diskutieren...

Nix inline-Assembler, das geht mit "__sync_synchronize" sowohl mit GCC 
als auch mit LLVM. Sinnigerweise kapselt man das mit einem eigenen 
Macro, falls man auf einen Compiler stößt, bei dem man es anders machen 
müßte.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Nix inline-Assembler, das geht mit "__sync_synchronize" sowohl mit GCC
> als auch mit LLVM.
Ah, weil compilerspezifische nichstandardisierte Builtins gleich viel 
besser sind als Assembler ;-) Vor C11 und C++11 haben die beiden 
Sprachen rein technisch gar kein Multithreading unterstützt, das wurde 
nur durch Spracherweiterungen möglich. C++11 hat dann Atomics 
eingeführt, und C hat sie abgekupfert - seitdem kann man 
plattformunabhängig und standardkonform mit Multithreading arbeiten, und 
das ganz ohne volatile. Atomics können einem aber leicht einen Knoten 
ins Hirn machen...

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
>> Aber das muss im Controller-Umfeld nicht unbedingt ein grosses Problem
>> sein.
>
> Ist es aber. Da es keine Standards gibt, sondern nur proprietäres
> Gefrickel

Wenn sich jemand bei einer bestimmten Lösung für eine bestimmtes 
Werkzeug entscheidet, dann kann das auch sinnvoll sein. Auch dann, wenn 
er sich mit diesem Werkzeug festlegt. Das ist seine Entscheidung.

Ich würde auch empfehlen, den Begriff "Gefrickel" nicht 
überzustrapazieren. Es sei denn man ist ohnehin auf Kravall aus. Nicht 
jede spezielle Lösung ist schon deshalb Gefrickel, weil sie speziell 
ist.

Apropos Wirth: In diesem Sinn war Wirth ein Frickler erster Güte ;-). 
Seine Philosophie war nämlich, sich für jedes Problem, das er nicht mit 
einem seiner bestehendene Werkzeug sauber abdecken konnte, ein neues 
Werkzeug zu schaffen. Standards, Multiplattformfähigkeit und 
Vendor-Lockin hat ihn wenig interessiert (als Prof konnte ihm das auch 
egal sein).

von Nop (Gast)


Lesenswert?

mh schrieb:

> In dem Fall muss der Zugriff aber auch atomar sein.

Nein, muß er nicht. Immerhin hat man ja drei Variablen: Lese-Index, 
Schreib-Index und Buffer. Man muß das halt in der richtigen Reihenfolge 
machen und sich ggf. lokale Kopien der Indices anlegen, auf denen man 
arbeitet. Das ist eigentlich ziemlich straight-forward.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Ah, weil compilerspezifische nichstandardisierte Builtins gleich viel
> besser sind als Assembler ;-)

Wieso, wenn man, wie ich sagte, mit einem eigenen Macro kapselt, dann 
ist sowas nicht weiter wild.

von mh (Gast)


Lesenswert?

A. K. schrieb:
> Ohne "volatile" bei "flag" wird ein optimierender Compiler in f() nicht
> jedesmal in der Schleife auf "flag" zugreifen, sondern genau 1x am
> Anfang und von der Änderung nichts mitkriegen.

Ja, in deinem Beispiel stimmt das. Aber der Compiler darf alles 
(natürlich nicht wirklich alles ;-) ) was nicht volatile ist um die 
volatile Zugriffe anders anordnen.

Wenn der Inhalt deiner for-Schleife so aussieht:
1
int foo = 0;
2
if (flag) {
3
   foo = f();
4
   flag = false;
5
}
6
// mache was mit foo
Und f sieht so aus:
1
int f() {
2
// ... berechne Wert ...
3
  return Wert;
4
}


dann kann der Compiler daraus
1
int foo = f();
2
if (flag) {
3
   flag = false;
4
}
5
else {
6
f = 0;
7
}
8
// mache was mit foo
machen, solange er sehen kann das f keine Nebeneffekte hat. Das in 
diesem Fall nicht sinnvoll und nicht wirklich schädlich, kann aber 
schnell ein Problem werden wenn das Flag andere Daten schützt, die im 
Handler gesetzt werden.

von Nop (Gast)


Lesenswert?

A. K. schrieb:
> Nicht
> jede spezielle Lösung ist schon deshalb Gefrickel, weil sie speziell
> ist.

Ich hab seinerzeit genug Frust mit der Balkanisierung von Pascal gehabt, 
weil im Unterricht Turbo-Pascal eingesetzt wurde, ich aber einen Atari 
ST hatte und mir somit ST-Pascal verfügbar gewesen wäre. 
Selbstverständlich inkompatibel. Mit C wäre das alles kein Problem 
gewesen, aber mit Pascal gab's dann abenteuerliche Klimmzüge, die allein 
dem Pascal-Sprachgefrickel geschuldet waren.

von mh (Gast)


Lesenswert?

Dr. Sommer schrieb:
> mh schrieb:
>> Die schreibenden Zugriffe auf a
>> und b in thread1 dürfen nicht vertauscht werden weil a und b volatile
>> sind.
> Vom Compiler nicht. Der Prozessor weiß davon nix und kann die anordnen
> wie er lustig ist.

Ist das so? Der Standard sagt soweit ich weiß, dass die Zugriffe nicht 
vertauscht werden dürfen und unterscheidet nicht zwischen Compiler und 
CPU. Also muss der Compiler dafür sorgen, dass die CPU nichts vertauscht 
(? oder .)

von Dr. Sommer (Gast)


Lesenswert?

mh schrieb:
> Ist das so?
Lies doch meinen Link. Der Standard würde wohl kaum explizit 
vorschreiben, dass Atomics eine Reihenfolge definieren, wenn volatile 
Variablen es auch täten. Wie gesagt, alte C Standards können eigentlich 
kein Multithreading, und das dort enthaltene volatile ist nicht dafür 
gedacht oder geeignet.

von Dr. Sommer (Gast)


Lesenswert?

mh schrieb:
> Ist das so?
Kann man übrigens auch einfach ausprobieren:
1
#include <stdio.h>
2
3
void print (int x) {
4
  printf ("%d\n", x);
5
}
6
7
volatile int a = 0, b = 0;
8
void thread1(void) {
9
  a = 1;
10
  b = 2;
11
}
12
void thread2(void) {
13
  print (b);
14
  print (a);
15
}
wird zu
1
0000000000000000 <print>:
2
   0:  89 fa                  mov    %edi,%edx
3
   2:  be 00 00 00 00         mov    $0x0,%esi
4
   7:  bf 01 00 00 00         mov    $0x1,%edi
5
   c:  31 c0                  xor    %eax,%eax
6
   e:  e9 00 00 00 00         jmpq   13 <thread1>
7
8
0000000000000013 <thread1>:
9
  13:  c7 05 00 00 00 00 01   movl   $0x1,0x0(%rip)        # 1d <thread1+0xa>
10
  1a:  00 00 00 
11
  1d:  c7 05 00 00 00 00 02   movl   $0x2,0x0(%rip)        # 27 <thread1+0x14>
12
  24:  00 00 00 
13
  27:  c3                     retq   
14
15
0000000000000028 <thread2>:
16
  28:  48 83 ec 08            sub    $0x8,%rsp
17
  2c:  8b 3d 00 00 00 00      mov    0x0(%rip),%edi        # 32 <thread2+0xa>
18
  32:  e8 00 00 00 00         callq  37 <thread2+0xf>
19
  37:  8b 3d 00 00 00 00      mov    0x0(%rip),%edi        # 3d <thread2+0x15>
20
  3d:  58                     pop    %rax
21
  3e:  eb c0                  jmp    0 <print>
(printf ausgelagert um Code zu verkürzen). Ich seh da nix mit Memory 
Barriers oder Synchronisierung. Der Compiler weiß an der Stelle nicht, 
ob die beiden Funktionen nacheinander oder von verschiedenen Threads 
aufgerufen werden, kann hier also auch nichts optimieren.

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> gewesen, aber mit Pascal gab's dann abenteuerliche Klimmzüge, die allein
> dem Pascal-Sprachgefrickel geschuldet waren.

Ich will hier nicht speziell auf irgendein bestimmten Pascal raus. Oder 
auf irgendeine bestimmte Sprache. Sondern auf Entscheidungsprozesse 
allgemein.

Denk dir folgende Situation: Eine Firma A bringt eine neue Technik raus, 
neue geniale Hardware, eine neuen Sprache mit neuen Eigenschaften, egal.

Eine andere Firma B sieht im Gegensatz zur konservativen Konkurrenz 
frühzeitig das Potential und bringt auf dieser Basis ein Produkt, das 
halb so teuer oder doppelt so schnell ist wie die Konkurrenz. Eben weil 
sie als einzige oder zumindest erste auf etwas setzt, das neu ist und 
speziell.

Wenn das Zeug von Firma A rechtzeitig funktioniert, hat B gewonnen und 
die Konkurrenz hat ein grosses Problem. Wenn nicht, hat B ein Problem. 
Beides hat es in der Vergangenheit schon öfter gegeben. Das macht diese 
Entscheidung zu einer wesentlichen unternehmerischen Entscheidung. Aber 
Begriffe wie "Gefrickel" sind in hier Schwachsinn (auch wenn die im 
Gefolge eines Fehlschlags garantiert aufkommen ;-).

Deshalb: Nicht jede spezielle Lösung ist unangebracht. Es kann im 
Einzelfall mehr Kritierien geben als nur Standards. Oft sind es 
sinnvoll, der Herde zu folgen, aber nicht immer. Wenn eine neue Sprache, 
ob sie was mit Pascal zu tun hat oder nicht, besondere Mechanismen 
enthält, die ein neues Produkt wesentlich erleichtern, kann auch eine 
Einschränkung auf diese proprietäre oder exotische Sprache einen Sinn 
ergeben.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Der Standard würde wohl kaum explizit
> vorschreiben, dass Atomics eine Reihenfolge definieren, wenn volatile
> Variablen es auch täten.

Volatile verhindert das Umordnen der Zugriffe innerhalb eines Threads, 
verhindert aber nicht, dass sie mit Zugriffe in einem anderen Thread 
vertauscht werden. Atomics garantieren die Ordnung (und mehr) der 
Zugriffe in mehreren Threads.

von Nop (Gast)


Lesenswert?

mh schrieb:

> Volatile verhindert das Umordnen der Zugriffe innerhalb eines Threads

Jein. Das Gemeine ist, daß die nicht-volatile-Zugriffe sehr wohl über 
die volatile-Zugriffe hinweg umgeordnet werden dürfen.

von Dr. Sommer (Gast)


Lesenswert?

mh schrieb:
> Volatile verhindert das Umordnen der Zugriffe innerhalb eines Threads,
> verhindert aber nicht, dass sie mit Zugriffe in einem anderen Thread
> vertauscht werden.
Sag ich doch. Um die Synchronisierung zwischen mehreren Threads ging es 
ja die ganze Zeit. Schön dass du mir es jetzt glaubst...

von Nop (Gast)


Lesenswert?

A. K. schrieb:

> Ich will hier nicht speziell auf irgendein bestimmten Pascal raus. Oder
> auf irgendeine bestimmte Sprache. Sondern auf Entscheidungsprozesse
> allgemein.

Nur sind die in Bezug auf Sprachen eben doch etwas anders gelagert. Wenn 
da jeder abseits des Standards frickelt, weil es keinen brauchbaren 
Standard gibt und geben wird, dann ist das Ergebnis einfach nur 
Balkanisierung und Vendor-Lockin. Und, wie am Beispiel Pascal zu sehen, 
die Erosion der ganzen Sprache in die weitgehende Bedeutungslosigkeit. 
Und das obwohl Pascal sehr wohl Vorzüge hat, mit die es gegen C antreten 
hätte können - wenn es standardisiert gewesen wäre.

Der Grund ist fehlender Wettbewerb, weil es zwischen inkompatiblen 
Compilern keinen Wettbewerb gibt. Die Nutzer haben nämlich so hohe 
Opportunitätskosten beim Wechsel, daß er ohnehin kaum machbar ist.

Das ist eben anders, wenn alle Wettbewerber denselben Standard 
implementieren, weil die Entwicklung Standard-getrieben und nicht als 
Frickelei erfolgt. Dann ist die Frage nämlich nicht, wer coolere 
proprietäre Features frickelt, die die Nutzer binden, sondern wer den 
Standard besser implementiert.

von (prx) A. K. (prx)


Lesenswert?

Auch in der Frage atomarer Zugriffe kann ich mir vorstellen, dass man 
Sprachen schaffen kann, in denen es der Compiler selbst herausfinden 
kann, welche Zugriffe wie abgesichert werden müssen. Oder das Ausmass an 
Zugriffskonflikten durch andere Programmier-Paradigmata erheblich 
reduziert wird. Und der Programmierer nicht fast in Assembler-Manier 
jeden Kleinscheiss explizit modellieren muss, wie in C11.

Diese Sprache wird sicherlich nicht annähernd wie C aussehen, auch nicht 
wie ein bestehendes Pascal. Und es wird Fälle geben, in denen man mit 
den Freiheiten von C schneller ist als mit eher generischen Lösungen 
dieser Sprache. Aber umgekehrt könnte diese Sprache das Programmieren 
mit vielen Threads wesentlich erleichtern. Nicht immer ist das Tempo des 
Programms der wichtigste Faktor. Oft ist das Tempo des Programmierers 
wichtiger, oder die Zuverlässigkeit der Lösung.

Das fände ich interessanter als eine Neuauflage von der alten Frage, ob 
man das Ei am dicken oder dünnen Ende aufschlägt, bzw. ob Pascal oder C.

von Nop (Gast)


Lesenswert?

A. K. schrieb:
>  Und der Programmierer nicht fast in Assembler-Manier
> jeden Kleinscheiss explizit modellieren muss, wie in C11.

Aber dafür ist C doch gedacht, als portabler Makro-Assembler zur 
Systemprogrammierung.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Dann ist die Frage nämlich nicht, wer coolere
> proprietäre Features frickelt, die die Nutzer binden, sondern wer den
> Standard besser implementiert.
Schön wärs, wie oft passiert das in der Realität? Wer interessiert sich 
dafür, wie gut Windows den POSIX-Standard oder den OpenGL-Standard 
implementiert, wenn Windows das leistungsfähigere DirectX und Games 
bietet im Gegensatz zu z.B. Linux? Wer fragt danach wie gut der 
Microsoft C++ Compiler den C++ Standard implementiert (lange Zeit 
ziemlich schlecht), wenn Visual Studio die benutzerfreundlichste IDE auf 
der Plattform ist? Sinngemäß sieht man das doch ständig im Forum, wo 
über Keil, IAR & Konsorten geschwärmt wird, die noch teilweise nicht 
einmal versuchen aktuelle Sprachstandards zu implementieren, aber soo 
tolle IDE's bieten. Weiter geht's mit FTDI-IC's die ein proprietäres 
Protokoll statt USB-CDC nutzen, Office Suites die proprietäre Formate 
nutzen, die Liste lässt sich endlos fortsetzen.

A. K. schrieb:
> Auch in der Frage atomarer Zugriffe kann ich mir vorstellen, dass
> man
> Sprachen schaffen kann, in denen es der Compiler selbst herausfinden
> kann, welche Zugriffe wie abgesichert werden müssen.
Richtig, gibts schon länger als C, nämlich rein funktionale Sprachen.

von (prx) A. K. (prx)


Lesenswert?

Nop schrieb:
> Aber dafür ist C doch gedacht, als portabler Makro-Assembler zur
> Systemprogrammierung.

Aber vielleicht sind zwei falsche Lösungen nicht richtiger als eine. 
Also wenn man grad nicht dabei ist, ein Betriebssystem zu programmieren.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Dr. Sommer schrieb:
> mh schrieb:
>> Ist das so?
> Kann man übrigens auch einfach ausprobieren:

Das ist x86? Dann ist das nicht sehr aussagekräftig, da x86 ein sehr 
striktes (mir ist keine besseres Wort eingefallen) Memory Model hat und 
Writes nur unter speziellen Bedingungen umordnet. Nen Arm mit OoO wäre 
da interessanter.

Nop schrieb:
> mh schrieb:
>
>> Volatile verhindert das Umordnen der Zugriffe innerhalb eines Threads
>
> Jein. Das Gemeine ist, daß die nicht-volatile-Zugriffe sehr wohl über
> die volatile-Zugriffe hinweg umgeordnet werden dürfen.

Ich wollte auch nicht das Gegenteil behaupten, mein Beispiel mit foo = 
f() und flag beruht ja genau darauf.

Dr. Sommer schrieb:
> Sag ich doch. Um die Synchronisierung zwischen mehreren Threads ging es
> ja die ganze Zeit. Schön dass du mir es jetzt glaubst...

Ok, vllt. haben wir dann etwas aneinander vorbei geschrieben. Ich 
bestreite nicht, dass in deinem Beispiel die Ausgabe 2, 0 möglich ist. 
Das liegt aber nicht daran, dass die Zugriffe von a = 1; b = 2; anders 
angeordnet werden dürfen (dürfen sie nicht soweit ich weiß, weder 
Compiler noch CPU), sondern daran, dass ein anderer Thread diese 
Zugriffe nicht zwingen in der gleichen Reihenfolge sehen muss.

von Nop (Gast)


Lesenswert?

A. K. schrieb:

> Aber vielleicht sind zwei falsche Lösungen nicht richtiger als eine.
> Also wenn man grad nicht dabei ist, ein Betriebssystem zu programmieren.

Naja aber es ist doch relativ sinnfrei, sich darüber zu beklagen, daß C 
eben vorrangig darin gut ist, wofür es gedacht ist - wenn man eben was 
anderes will. Genauso ist Pascal als Lehrsprache durchaus gut, weil es 
Anfänger dazu zwingt, sich von vornherein über Datentypen Gedanken zu 
machen.

Dr. Sommer schrieb:

> Schön wärs, wie oft passiert das in der Realität?

Ziemlich oft, weswegen C und C++ weiterhin sehr wichtige Sprachen sind. 
Windows ist keine Sprache und kein Compiler, also andere Baustelle.

> Sinngemäß sieht man das doch ständig im Forum, wo
> über Keil, IAR & Konsorten geschwärmt wird, die noch teilweise nicht
> einmal versuchen aktuelle Sprachstandards zu implementieren

Irrelevant, denn sie implementieren überhaupt mal Standards, und 
deswegen kann man zwischen ihnen wechseln, wenn man will. Es ist nicht 
so, daß die bestehende Codebasis einen auf einen Hersteller festnageln 
würde, das ist der Punkt.

Es ist doch in der Realität weitgehend egal, wie sexy man einen Compiler 
findet, um ein neues Projekt zu starten. Der Knackpunkt ist doch, 
wieviel Aufwand es wäre, die bestehende Codebasis zu migrieren. 
Schließlich macht man weitaus mehr Bestandspflege als Neustart auf der 
grünen Wiese.

Allein schon die Drohung, daß man seinen Compiler wechseln KÖNNTE, 
bewirkt Wettbewerb - aber eben auch nur, wenn die Drohung mit einer 
bestehenden Codebasis realistisch ist.

von Dr. Sommer (Gast)


Lesenswert?

mh schrieb:
> Das ist x86?
Ja.

mh schrieb:
> Nen Arm mit OoO wäre da interessanter.
Hab ich grad keinen Compiler für, kannst du ja mal ausprobieren.

mh schrieb:
> sondern daran, dass ein anderer Thread diese
> Zugriffe nicht zwingen in der gleichen Reihenfolge sehen muss.
Das ist die abstrakte Sichtweise. Dass ein anderer Thread eine andere 
Reihenfolge beobachtet, kann (muss aber nicht) daran liegen, dass die 
tatsächlichen schreibenden Speicherzugriffe in anderer Reihenfolge 
passieren (z.B. die Reihenfolge in der Cache-Pages rausgeschrieben 
werden). Oder es liegt daran, dass der CPU des beobachtenden Threads die 
Pages in anderer Reihenfolge liest.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Irrelevant, denn sie implementieren überhaupt mal Standards, und
> deswegen kann man zwischen ihnen wechseln, wenn man will. Es ist nicht
> so, daß die bestehende Codebasis einen auf einen Hersteller festnageln
> würde, das ist der Punkt.
Tja, kompilier bspw. mal den LPC USB Stack mit dem GCC und freu dich 
über zufällige Hardfaults, weil der GCC undefiniertes Verhalten anders 
umsetzt als z.B. der Keil, mit welchem das wohl entwickelt wurde... ST 
versucht wenigstens, den GCC auch zu unterstützen.

Nop schrieb:
> aber eben auch nur, wenn die Drohung mit einer
> bestehenden Codebasis realistisch ist.
Genau, daher weichen schlaue Compilerhersteller auf subtile Art vom 
Standard ab, sodass man eben nicht mehr so leicht abhauen kann. Das ist 
doch Microsofts alte und bewährte Strategie...

Ich bin zwar auch sehr für einheitliche Standards, aber die Realität ist 
dann doch nicht ganz so rosig. Am Ende gewinnt doch der mit dem besseren 
Marketing...

von Alex G. (dragongamer)


Lesenswert?

A. K. schrieb:
> Auch in der Frage atomarer Zugriffe kann ich mir vorstellen, dass man
> Sprachen schaffen kann, in denen es der Compiler selbst herausfinden
> kann, welche Zugriffe wie abgesichert werden müssen. Oder das Ausmass an
> Zugriffskonflikten durch andere Programmier-Paradigmata erheblich
> reduziert wird. Und der Programmierer nicht fast in Assembler-Manier
> jeden Kleinscheiss explizit modellieren muss, wie in C11.
>
> Diese Sprache wird sicherlich nicht annähernd wie C aussehen, auch nicht
> wie ein bestehendes Pascal. Und es wird Fälle geben, in denen man mit
> den Freiheiten von C schneller ist als mit eher generischen Lösungen
> dieser Sprache. Aber umgekehrt könnte diese Sprache das Programmieren
> mit vielen Threads wesentlich erleichtern. Nicht immer ist das Tempo des
> Programms der wichtigste Faktor. Oft ist das Tempo des Programmierers
> wichtiger, oder die Zuverlässigkeit der Lösung.
>
> Das fände ich interessanter als eine Neuauflage von der alten Frage, ob
> man das Ei am dicken oder dünnen Ende aufschlägt, bzw. ob Pascal oder C.

Die Sprache von der du redest heisst GO!
Diese wurde mit den Bedürfnissen von Multithreading (in relativ großem 
Stil) im Fokus entwickelt.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> weil der GCC undefiniertes Verhalten anders umsetzt

Undefiniertes Verhalten (gemäß Standard) ist exakt das. Wer sich auf ein 
bestimmtes undefiniertes Verhalten verläßt, dem ist eh nicht mehr zu 
helfen.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Wer sich auf ein bestimmtes undefiniertes Verhalten verläßt, dem ist eh
> nicht mehr zu helfen.

Jo. Sag das NXP. Auch im ST Code grassieren Dinge wie verbotene 
Bezeichner. Hier im Forum werden oft kategorisch die korrekten Lösungen 
abgelehnt und stattdessen undefinierte Frickelei bevorzugt, wie bspw. 
Pointer umcasten und unions zum Daten konvertieren zu nutzen, um sich 
dann über unerwartetes Verhalten zu wundern.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> IAR & Konsorten geschwärmt wird, die noch teilweise nicht einmal
> versuchen aktuelle Sprachstandards zu implementieren

Kennst du IAR wirklich?  Meiner Meinung nach tust du ihnen damit
grob unrecht.  Die hatten bspw. eine C99-Standard-Bibliothek, als
man im GCC-Umfeld davon nur träumen konnte.

Deren IDE habe ich nicht benutzt, aber der Compiler ist wirklich gut.
Eine einzige Sache habe ich in Erinnerung, bei der sie ziemlich dünn
sind: inline asm constraining.  Das macht inline asm praktisch nutzlos,
denn das Einzige, auf was man sich darin verlassen kann, sind globale
Variable (aber dann könnte ich auch gleich die komplette Funktion in
Assembler schreiben).  Das inline asm constraining des GCC versteht
man zwar wohl nur dann völlig, wenn man den Compiler versteht :), aber
es gibt einem System(bibliotheks)programmierer ein mächtiges Werkzeug,
welches man gerade im Embedded-Bereich gut benötigen kann.

von (prx) A. K. (prx)


Lesenswert?

Jörg W. schrieb:
> Das inline asm constraining des GCC versteht
> man zwar wohl nur dann völlig, wenn man den Compiler versteht :), aber
> es gibt einem System(bibliotheks)programmierer ein mächtiges Werkzeug,
> welches man gerade im Embedded-Bereich gut benötigen kann.

Das Inline-ASM vom GCC ist enorm mächtig, gerade weil es sich nicht nur 
dazu eignet, ASM Funktionen zu schreiben, sondern sich recht weitgehend 
in die Optimierung des Compilers integriert und man oft nur sehr wenig 
ASM braucht, da der Compiler den Rest von sich aus erledigt. Aber wie 
viele mächtigen Werkzeuge eignet es sich auch vorzüglich dazu, sich in 
den Fuss zu schiessen.

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


Lesenswert?

A. K. schrieb:
> Aber wie viele mächtigen Werkzeuge eignet es sich auch vorzüglich dazu,
> sich in den Fuss zu schiessen.

Uneingeschränkte Zustimmung. :)  Ist mir aber trotzdem viel lieber
als das impotente inline asm des IAR.  Da schreiben die Leute nämlich
dann inline asm statements, die sich auf implizite Annahmen (wie
lokale Variablen in Registern) verlassen, die sie per trial&error
ermittelt haben und die bereits in der nächsten Compilerversion
hinfällig sein können.  Da weiß man dann gar nicht mehr, warum der
Fuß plötzlich weh tut. :-))

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Jo. Sag das NXP. Auch im ST Code grassieren Dinge wie verbotene
> Bezeichner.

Daß Software von Hardwarefirmen nicht unbedingt der Hit ist, kann ja nun 
keinen verwundern.

> Pointer umcasten und unions zum Daten konvertieren zu nutzen

Type punning über unions ist seit C99 einer der beiden korrekten Wege, 
das zu tun.

Pointercasting ist abgesehen von wenigen Ausnahmen (char * darf alles 
aliasen) undefiniertes Verhalten. Da, wo es im Code nicht zu vermeiden 
ist, muß man striktes Aliasing im Build abschalten. Du nutzt direkt oder 
indirekt übrigens jeden Tag Code, bei dem das so ist - alles, was mit 
Linux gebaut wurde nämlich.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Type punning über unions ist seit C99 einer der beiden korrekten Wege,
> das zu tun.
Der ist zwar erlaubt, aber das Ergebnis ist dennoch undefiniert (hängt 
bspw. von der Byte-Reihenfolge der Plattform ab). Und in C++ ists immer 
noch verboten.

Nop schrieb:
> Daß Software von Hardwarefirmen nicht unbedingt der Hit ist, kann ja nun
> keinen verwundern.
Dass sich Weltkonzerne wie ST keine kompetenten Informatiker leisten 
können wundert mich doch etwas.

Nop schrieb:
> Da, wo es im Code nicht zu vermeiden
> ist, muß man striktes Aliasing im Build abschalten.
An welchen Stellen ist es denn wirklich unvermeidbar? Mir fällt keine 
ein außer Register-Zugriffen, und das fällt glaube ich nicht unter 
Strict Aliasing...

Nop schrieb:
> Du nutzt direkt oder
> indirekt übrigens jeden Tag Code, bei dem das so ist - alles, was mit
> Linux gebaut wurde nämlich.
Die Code-Qualität des Linux Kernels ist ohnehin... kaum in Worte zu 
fassen?

Jörg W. schrieb:
> Kennst du IAR wirklich?
Ok, mit IAR war nur einfach ein proprietärer geraten. Hier bspw. 
http://en.cppreference.com/w/cpp/compiler_support sieht man bei den 
proprietären ganz viel rot...

von mh (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Und in C++ ists immer
> noch verboten.
Das stimmt so nicht allgemein. Aus dem c++17 draft (N4687 §12.2.24)
1
In a standard-layout union with an active member (12.3) of struct type T1,
2
it is permitted to read a non-static data member m of another union member of
3
struct type T2 provided m is part of the common initial sequence of T1 and T2;
4
the behavior is as if the corresponding member of T1 were nominated.
5
[ Example:
6
struct T1 { int a, b; };
7
struct T2 { int c; double d; };
8
union U { T1 t1; T2 t2; };
9
int f() {
10
U u = { { 1, 2 } }; // active member is t1
11
return u.t2.c; // OK, as if u.t1.a were nominated
12
}
13
— end example ]

von Dr. Sommer (Gast)


Lesenswert?

mh schrieb:
> Das stimmt so nicht allgemein.
Toll, man kann Variablen gleichen Typs auslesen. Kann man ja super zum 
Daten konvertieren nutzen!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:

> Jörg W. schrieb:
>> Kennst du IAR wirklich?
> Ok, mit IAR war nur einfach ein proprietärer geraten. Hier bspw.
> http://en.cppreference.com/w/cpp/compiler_support sieht man bei den
> proprietären ganz viel rot...

Da ist IAR nicht dabei.

Allerdings kann ich zu neueren C++-Standards da auch nicht mehr viel
sagen; ist zu lange her, dass ich ihn mal in den Fingern hatte.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Der ist zwar erlaubt, aber das Ergebnis ist dennoch undefiniert

Nein, ist es nicht.

> (hängt bspw. von der Byte-Reihenfolge der Plattform ab).

Das ist implementation defined, nicht undefined. Undefined hieße 
beispielsweise, daß der Compiler das komplett wegoptimieren könnte - 
inklusive dem ganzen Rest des Programms.

Ich hab schon type punning benutzt, wenn ich structs hatte, die aus 4 
Bytes bestanden, die man aber mit einer Union auf uint32_t alle zusammen 
nicht nur nullen kann, sondern auch kopieren und vergleichen. Wo 
innerhalb des uint32_t welches Byte landet, ist dafür egal.

> Und in C++ ists immer noch verboten.

Das schon.

> Dass sich Weltkonzerne wie ST keine kompetenten Informatiker leisten
> können wundert mich doch etwas.

Dürfte mit der Firmenkultur zu tun haben. Wenn man sich als 
Hardwarefirma versteht, dann gilt Software eher so als Dreingabe. Daß 
man wesentlich mehr Hardware verkaufen kann, wenn man sie den 
potentiellen Kunden mundgerecht vorlegt, ist eine Erkenntnis, die den 
Firmen immer noch neu ist.

> An welchen Stellen ist es denn wirklich unvermeidbar? Mir fällt keine
> ein außer Register-Zugriffen, und das fällt glaube ich nicht unter
> Strict Aliasing...

Beispielsweise, wenn man in C etwas memcpy-artiges programmieren will, 
was schneller als byteweises Kopieren geht.

Bei Pascal ist es eine der Kritiken, daß zwar Funktionen mit variabler 
Argumentzahl vorkommen, man selber aber keine definieren kann. Dieselbe 
Kritik muß sich dann C an dieser Stelle auch gefallen lassen.

> Die Code-Qualität des Linux Kernels ist ohnehin... kaum in Worte zu
> fassen?

Der Linuxkernel ist einfach nur sehr systemnah. Mal so vermutet, wo ich 
das plausibel fände:

Wenn man beispielsweise einen Datenblob von einem Treiber bekommt, den 
man interpretieren oder auch modifizieren will, dann möchte man kein 
memcpy machen. Dann würde die Sache nämlich drastisch langsamer, falls 
der Compiler gerade mal nicht fähig ist, das memcpy wegzupotimieren.

Etwa im Beispiel des Netzwerkstacks hängt ja das Format bestimmter 
Pakete überhaupt erst von einem Paket-Identifier ab. Da ein struct 
drüberzucasten und ggf. die relevanten Felder endianess-mäßig mit den 
host/network-Macros zu behandeln, ist da wohl der Weg der Wahl.

von Wilhelm M. (wimalopaan)


Lesenswert?

Nop schrieb:
> Dr. Sommer schrieb:
>
>> Der ist zwar erlaubt, aber das Ergebnis ist dennoch undefiniert
>
> Nein, ist es nicht.
>
>> (hängt bspw. von der Byte-Reihenfolge der Plattform ab).
>
> Das ist implementation defined, nicht undefined. Undefined hieße
> beispielsweise, daß der Compiler das komplett wegoptimieren könnte -
> inklusive dem ganzen Rest des Programms.
>
> Ich hab schon type punning benutzt, wenn ich structs hatte, die aus 4
> Bytes bestanden, die man aber mit einer Union auf uint32_t alle zusammen
> nicht nur nullen kann, sondern auch kopieren und vergleichen. Wo
> innerhalb des uint32_t welches Byte landet, ist dafür egal.

Das UB entsteht durch das Lesen des nicht-aktiven members der union.

Das IB entsteht durch die endianness.

Beides lässt sich aber lösen.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Das ist implementation defined, nicht undefined.
Achja, richtig. Was ich eigentlich sagen wollte ist, dass man sich hier 
oft gewundert wird, warum so etwas nicht immer tut was man will:
1
void test (void) {
2
  uint32_t a = 0xAABBCCDD;
3
  char b = ((char*) a) [2];
4
  assert (b == 0xBB);
5
}
Der cast nach "char*" und Dereferenzierung ist ja sogar erlaubt, aber 
das Ergebnis ist dennoch nicht was man haben wollte, weil keiner sich 
die Mühe macht dem Standard zu folgen.

Nop schrieb:
> Beispielsweise, wenn man in C etwas memcpy-artiges programmieren will,
> was schneller als byteweises Kopieren geht.
memcpy sollte bei guten Compilern auch nicht Byteweise, sondern i.A. 
effizient sein. Das ist dann aber Teil der Plattform (Compiler+C 
Library) und kann in der Tat nicht korrekt in C implementiert werden 
(außer man schaltet Strict Aliasing ab, was ja dann nicht 
Standard-Konform ist).

Nop schrieb:
> Dieselbe
> Kritik muß sich dann C an dieser Stelle auch gefallen lassen.
C++ kann's!

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Dann würde die Sache nämlich drastisch langsamer, falls
> der Compiler gerade mal nicht fähig ist, das memcpy wegzupotimieren.
Dafür muss man dann aber das strict Aliasing abschalten, was wiederum 
eine Menge Optimierungen verhindert. Man könnte in solchen Fällen auch 
korrekt mit Bit-Operationen arbeiten, aber das ist, insb. in C, viel 
Tipparbeit.

von Nop (Gast)


Lesenswert?

Wilhelm M. schrieb:

> Das UB entsteht durch das Lesen des nicht-aktiven members der union.

In C99 nicht. Natürlich geht das nur, wenn wir hier von gleichen Größen 
reden. Etwa einen 4-Byte-float schreiben und einen drüberliegenden 
uint32_t lesen geht.

Aber wenn man einen uint8_t schreibt und dann den uint32_t liest, steht 
logischerweise nicht fest, was denn in den anderen drei Bytes des 
uint32_t ist.

Dr. Sommer schrieb:

>   uint32_t a = 0xAABBCCDD;
>   char b = ((char*) a) [2];

Meintest Du "&a"?

> das Ergebnis ist dennoch nicht was man haben wollte

Kommt drauf an, vielleicht wollte man ja einen Endianess-Test schreiben.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Meintest Du "&a"?
Äh ja, natürlich.

Nop schrieb:
> Kommt drauf an, vielleicht wollte man ja einen Endianess-Test schreiben.
... den man in korrektem C grundsätzlich nicht braucht, denn wenn man 
Daten-Konvertierungen nur über Bitoperationen durchführt, wird das vom 
Compiler automatisch korrekt gemacht! Aber wenn man schon bei 
Nicht-Standard-Code ist, kann man auch _BYTE_ORDER_ o.ä. nutzen...

von Wilhelm M. (wimalopaan)


Lesenswert?

Nop schrieb:
> Wilhelm M. schrieb:
>
>> Das UB entsteht durch das Lesen des nicht-aktiven members der union.
>
> In C99 nicht. Natürlich geht das nur, wenn wir hier von gleichen Größen
> reden. Etwa einen 4-Byte-float schreiben und einen drüberliegenden
> uint32_t lesen geht.

Es bezog sich ja auf C++.

Ab C99 ist das explizit erlaubt.

In C++ (schon immer) explizit verboten wegen UB (Ctor/dtor-Prolematik).

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Nop schrieb:
>> Meintest Du "&a"?
> Äh ja, natürlich.
>
> Nop schrieb:
>> Kommt drauf an, vielleicht wollte man ja einen Endianess-Test schreiben.
> ... den man in korrektem C grundsätzlich nicht braucht, denn wenn man
> Daten-Konvertierungen nur über Bitoperationen durchführt, wird das vom
> Compiler automatisch korrekt gemacht! Aber wenn man schon bei
> Nicht-Standard-Code ist, kann man auch _BYTE_ORDER_ o.ä. nutzen...

Oder std::endian

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Dafür muss man dann aber das strict Aliasing abschalten, was wiederum
> eine Menge Optimierungen verhindert.

Ja sicher, genau das tut man beim Build des Kernels ja auch. Jedenfalls 
seit strict aliasing auf einmal Default des GCC wurde, ich glaube bei 
4.9 oder so. Ich entsinne mich, daß Torvalds sich über diese 
Default-Änderung ziemlich aufgeregt hat.

Andererseits muß man auch konkret nachmessen, ob strict aliasing 
überhaupt Vorteile bringt. Bei dem Code, den ich bisher hatte, war da 
gar nichts meßbar. Deswegen schalte ich es jedenfalls zum Release 
einfach ab. Selbst in Benchmarks geht's da um kaum mehr als 1-2% oder so 
(IIRC).

Selbst bei heftig numerischem Code bringt es wenig, weil das Aliasing 
kompatibler Datentypen (z.B. die ganzen doubles in Matrizen und 
Vektoren) immer noch da ist, und das kriegt man dann mit "restrict" in 
den Griff - welches aber auch bei abgeschaltetem strict aliasing geht.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

>> Kommt drauf an, vielleicht wollte man ja einen Endianess-Test schreiben.
> ... den man in korrektem C grundsätzlich nicht braucht

Datentausch mit anderen Systemen?

> Daten-Konvertierungen nur über Bitoperationen durchführt

Um das zu machen, muß man aber vorher schon die eigene Endianess wissen?

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Datentausch mit anderen Systemen?
Nop schrieb:
> Um das zu machen, muß man aber vorher schon die eigene Endianess wissen?
Eben nicht, das ist ja der Witz. Angenommen, wir wollen einen Little 
Endian 4-Byte vorzeichenlosen Integer aus einer Datei einlesen:
1
uint32_t convert (FILE* f) {
2
  unsigned char data [4];
3
  if (fread (data, 1, 4, f) != 4) return 0;
4
  return ((uint32_t) data[0])
5
       | (((uint32_t) data[1]) << 8)
6
       | (((uint32_t) data[2]) << 16)
7
       | (((uint32_t) data[3]) << 24);
8
}
Dann wird hier der Integer in der Reihenfolge der Host-Plattform 
zurückgegeben - automatisch korrekt BE/LE/Whatever. Für diesen Code muss 
man die eigene Reihenfolge überhaupt nicht wissen. Der Compiler weiß 
schon, ob "<<" im Speicher nach "oben" oder "unten" shiftet (d.h. ob 
höherwertige Bits "oben" oder "unten" gespeichert werden). Dieser Code 
wird von Compilern natürlich auch optimiert, also wenn kein 
Byte-Tauschen nötig ist weil die Reihenfolge passt, wird da auch nix 
gemacht. Und das alles ohne undefiniertes/implementation defined 
Behaviour oder Abschalten von Strict Aliasing usw.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Dann wird hier der Integer in der Reihenfolge der Host-Plattform
> zurückgegeben - automatisch korrekt BE/LE/Whatever.

Ooops. Mir fällt gerade auf, daß ich das EXAKT so auch schon 
implementiert habe. Bei der Ausgabe auf der anderen Seite 
dementsprechend auch, so daß das Format der gespeicherten Daten auch da 
nicht von der Endianess der speichernden Partei abhing. :-)

> Und das alles ohne undefiniertes/implementation defined
> Behaviour oder Abschalten von Strict Aliasing usw.

Wird halt nochmal anders, wenn Du IP-Pakete hast, die je nach 
Format-Byte im Header einen ganz unterschiedlichen folgenden Aufbau 
haben können. Daß man da mit Pointercasting arbeitet, kann ich 
nachvollziehen. Ansonsten (also mit memcpy) würde man riskieren, daß bei 
sonstigen Code-Änderungen oder Compiler-Updates als Seiteneffekt das 
Wegoptimieren nicht mehr klappt. Was entsprechend ätzend zu debuggen 
wäre.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Wird halt nochmal anders, wenn Du IP-Pakete hast, die je nach
> Format-Byte im Header einen ganz unterschiedlichen folgenden Aufbau
> haben können.
Hm, warum? Man baut ein paar Fallunterscheidungen ein - je nach 
Format-Byte konvertiert man den Payload halt anders und speichert das 
Ergebnis in ein jeweils anderes struct. Die kann man sogar per union 
"übereinander" speichern um Speicher zu sparen (nicht zum 
Konvertieren!).

Nop schrieb:
> Daß man da mit Pointercasting arbeitet, kann ich
> nachvollziehen.
Der einzige wirkliche Grund dafür ist, dass Konvertieren über Bitshifts 
viel Tipparbeit ist.

Nop schrieb:
> Ansonsten (also mit memcpy) würde man riskieren, daß bei
> sonstigen Code-Änderungen oder Compiler-Updates als Seiteneffekt das
> Wegoptimieren nicht mehr klappt. Was entsprechend ätzend zu debuggen
> wäre.
Aber memcpy ist doch eh nicht zum konvertieren geeignet 
(Byte-Reihenfolge usw.). Und ich debugge lieber ein Performance-Problem 
als kurioses Fehlverhalten bei Compiler-Update...

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Format-Byte konvertiert man den Payload halt anders und speichert das
> Ergebnis in ein jeweils anderes struct.

Eben letzteres wäre Kopieren, und das will man ja vermeiden.

> Und ich debugge lieber ein Performance-Problem
> als kurioses Fehlverhalten bei Compiler-Update...

Wenn man strict-aliasing abschaltet, hat man bei einem Compiler-Update 
kein Fehlverhalten. Nur als das per Default eingeführt wurde, wird man 
das sicherlich gehabt haben - wenn man dann auch noch die Releasenotes 
nicht gelesen hat.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Eben letzteres wäre Kopieren, und das will man ja vermeiden.
Ich verstehe dein Problem nicht. Ob man jetzt per Fallunterscheidung auf 
unterschiedliche Member einer union die sich in einem umgecasteten 
struct befindet zugreift, oder per Fallunterscheidung die Bytes 
unterschiedlich konvertiert, macht jetzt keinen großen Unterschied.

Nop schrieb:
> Wenn man strict-aliasing abschaltet, hat man bei einem Compiler-Update
> kein Fehlverhalten.
Es sei denn das Verhalten des Compilers ändert sich nochmal irgendwie, 
worauf man sich ja nicht verlassen kann, weil Code ohne strict aliasing 
vom Standard nicht abgedeckt ist.

von Tina (Gast)


Lesenswert?

schön, das solche C Konversationen grundsätzlich kontrovers sind..der 
Themenstarter ist dadurch nicht ein Stück weiter....
Also
Pascal
Python
Java
welche Alternativen gibt es noch?


Der Quatsch mit den Standard von Pascal kann man sich auch sparen.+Der 
Standard ist Delphi/Freepascal

Und ja, es gibt kleinste Unterschiede zu Mikroe oder AVRco Pascal, 
genauso wie es bei C verschiedende Varianten gibt als auch bei 
Python..als spart man sich den Zirkus an Diskussion und sollte 
vielleicht mal wieder zum Thema Zurück

Jemand der in Cöfter arbeitet hat mit den kleinen Unterschieden der 
Versionen genauso wenig Probleme wie jemand der in PAscal oder Python 
schreibt.
Schlussendlich Programmiert man ja nur mit z.B: Freepascal und Mikroe 
Pascal.
Das ist dann kein Drama..genauso wie andere in C mit gcc und VC arbeiten 
und da auch mit Unterschiefen leben müssen.
Schlussendlich kommt man mit allen Sprachen ans Ziel, weshalb solceh 
Diskussionen müßig sind

von Markus F. (mfro)


Lesenswert?

Tina schrieb:
> Jemand der in Cöfter arbeitet

wo genau liegt denn das?

von Dr. Sommer (Gast)


Lesenswert?

Tina schrieb:
> Schlussendlich kommt man mit allen Sprachen ans Ziel, weshalb solceh
> Diskussionen müßig sind
Na dann ist ja gut, wenn die Sprachauswahl derart irrelevant ist. 
Komisch, dass es trotzdem so viele verschiedene gibt.

von W.S. (Gast)


Lesenswert?

A. K. schrieb:
> Ich bin konkret weder mit
> Delphi noch sonst einem halbwegs aktuellen Pascal näher vertraut

Ja, das merkt man deutlich.

Ich will da aber nicht weiter drauf herumreiten, weil sonst alle, die 
nur C und sonst nix kennen, mir "Missionieren" vorwerfen. Vorsorglich 
verweise ich dazu auf Adenauer.

Ansonsten scheinen wir beim Thema "StLib des Grauens" und einschlägiger 
anderer Hersteller-Libs und -IDe's etc. ähnlicher nsicht zu sein. Meine 
kennst du ja: Texteditor, Totalcommander als IDE, Batchdatei als Make 
all" und die eigentliche Toolchain, bei ARM eben Keil. Hab mich einmal 
bei der Lernbetty mit dem Gcc herumgeärgert, geht zwar, aber wenn ich 
nicht muß, nehme ich den Gcc auch nicht.

W.S.

von Carl D. (jcw2)


Lesenswert?

Markus F. schrieb:
> Tina schrieb:
>> Jemand der in Cöfter arbeitet
>
> wo genau liegt denn das?

Direkt neben Unterschiefen.

von Tina (Gast)


Lesenswert?

owe....und genau an diesem Punkt merkt man was für Leute hier ihre 
Argumente vortragen..viel Spaß noch....
Nur Kindergarten hier..er hat kaka gesagt...lol

von Small Is Beautiful (Gast)


Lesenswert?

Markus F. schrieb:
> wie wär's mit Ada?
>
> https://www.adacore.com/download

in 
gnat-gpl-2017-arm-elf-linux-bin/share/examples/gnat-cross/led_flasher-st 
m32f4  ist ein Beispiel:
1
   text    data     bss     dec     hex filename
2
  56860    3652   30504   91016   16388 obj/led_flasher

Ich glaub das ist ein neure Weltrekord!
led_flasher läßt 2 LEDs blinken und fragt einen Taster ab.

Mit nur 60 kByte Flash und 34 kByte SRAM eine super Leistung ;->

von Markus F. (mfro)


Lesenswert?

Small Is Beautiful schrieb:
> Mit nur 60 kByte Flash und 34 kByte SRAM eine super Leistung ;->

wenn Du schlanke Programme haben willst, musst Du mit dem zfp Profil 
compilieren ...

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Ich will da aber nicht weiter drauf herumreiten,

Schade. Denn von ihm werde ich sicherlich keine Antwort darauf erhalten:

A. K. schrieb:
> weshalb ich deren Konzepte zur Kennzeichnung oder Vermeidung
> nebenläufigen Zugriffs nicht kenne. Genau die würden mich ja
> interessieren.

: Bearbeitet durch User
von Small Is Beautiful (Gast)


Lesenswert?

Markus F. schrieb:

> wenn Du schlanke Programme haben willst, musst Du mit dem zfp Profil
> compilieren ...

Wenn ich "zfp-stm32f4" verwende, bekomm ich:
"Ada.Interrupts" is not a predefined library unit"

Also entweder schlanke Programme oder Interrupts?

von Nop (Gast)


Lesenswert?

W.S. schrieb:
> Hab mich einmal bei der Lernbetty mit dem Gcc herumgeärgert

Abgesehen davon, daß die Syntax des Inline-Assemblers eine Frage der 
Gewohnheit ist, und daß das Aufsetzen des Linkerfiles nicht ganz trivial 
ist, was für Probleme gab es da?

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.