Forum: Compiler & IDEs ARM-GCC: No strict alias


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Walter T. (nicolas)


Lesenswert?

Guten Morgen,

die "strict aliasing rule" besagt ja, dass zwei Zeiger, die einer 
Funktion übergeben werden, vom Compiler als voneinander unabhängig 
betrachtet werden können, was gewisse Optimierungen (Variablen in 
Registern) erlaubt.

Eine Ausnahme ist ja die Standardfunktion memmove(), bei der sich die 
über die Zeiger bechriebenen Speicherbereiche überschneiden dürfen.

Ich habe gerade einen ähnlichen Fall, bei der einer Funktion einen 
Sende- und ein Empfangspuffer übergeben wird, wobei es durchaus nicht 
verboten sein soll, dass diese identisch sind.


1
/** Daten per SPI senden unter Zuhilfenahme des DMA
2
 *
3
 * Die funktion nutzt den DMA, um die maximale Datenrate zu erreichen. Sie 
4
 * ist allerdings nicht optimal schnell, da sie erst zurueckkehrt, wenn 
5
 * alles ubertragen ist. Optimierungpotenzial ist also vorhanden, aber 
6
 * momentan unnoetig, da selbst bei einem TFT das Update ausreichend
7
 * schnell ist.
8
 *
9
 * @param[out] receive: Daten von Slave
10
 * @param[in] send:  Daten an Slave
11
 * @param[in] len: Pufferlaenge, maximal 65536
12
 *
13
 * Gilt receive == send, wird der Puffer ueberschrieben
14
 * Gilt receive == NULL wird nur geschrieben, nichts gelesen
15
 * Gilt send == NULL werden nur Nullen geschrieben */
16
void spi_dma_transmitbuffer(uint8_t *receive, const uint8_t *send, uint16_t len)
17
{
18
  SPI_TypeDef* SPIx;
19
  DMA_Stream_TypeDef *DMA_StreamTx, *DMA_StreamRx;
20
  uint32_t            DMA_FlagTcif_Tx, DMA_FlagTcif_Rx;
21
22
  switch( SPI_HARD_DMA )
23
  {
24
    case spi_hard_none:
25
      /* Keine Hardware-SPI-Unterstuetzung */
26
      return;
27
28
    case spi_hard_STM32F4XX_SPI1_PA5_PA6_PA7:
29
      SPIx = SPI1;
30
      DMA_StreamTx = DMA2_Stream3;
31
      DMA_StreamRx = DMA2_Stream2;
32
      DMA_FlagTcif_Tx = DMA_FLAG_TCIF3;
33
      DMA_FlagTcif_Rx = DMA_FLAG_TCIF2;
34
      break;
35
36
    case spi_hard_STM32F4XX_SPI2_PB13_PB14_PB15:
37
      SPIx = SPI2;
38
      DMA_StreamTx = DMA1_Stream4;
39
      DMA_StreamRx = DMA1_Stream3;
40
      DMA_FlagTcif_Tx = DMA_FLAG_TCIF4;
41
      DMA_FlagTcif_Rx = DMA_FLAG_TCIF3;
42
      break;
43
44
    case spi_hard_STM32F4XX_SPI3_PC10_PC11_PC12:
45
      SPIx = SPI3;
46
      DMA_StreamTx = DMA1_Stream5;
47
      DMA_StreamRx = DMA1_Stream2;
48
      DMA_FlagTcif_Tx = DMA_FLAG_TCIF5;
49
      DMA_FlagTcif_Rx = DMA_FLAG_TCIF2;
50
      break;
51
  }
52
53
  /* Vorzeitig abbrechen, wenn nichts gesendet werden soll */
54
  if( len == 0 )
55
    return;
56
57
58
  /* Ungenutzte Puffer beruecksichtigen */
59
  const uint32_t CR_MINC = 1<<10;
60
  uint8_t tempRx;
61
  uint8_t tempTx = 0;
62
63
  if ( receive == NULL )
64
  {
65
    /* Keine Daten lesen */
66
    DMA_StreamRx->M0AR = (uint32_t) &tempRx;
67
    DMA_StreamRx->CR &= ~CR_MINC; /* nicht inkrementieren */
68
  }
69
  else
70
  {
71
    /* Neuen Block fuers lesen vorbereiten */
72
    DMA_StreamRx->M0AR = (uint32_t) receive;
73
    DMA_StreamRx->CR |= CR_MINC; /* inkrementieren */
74
  }
75
76
  if ( send == NULL )
77
  {
78
    /* Keine Daten senden */
79
    DMA_StreamTx->M0AR = (uint32_t) &tempTx;
80
    DMA_StreamTx->CR &= ~CR_MINC; /* nicht inkrementieren */
81
  }
82
  else
83
  {
84
    /* Neuen Block fuers senden vorbereiten */
85
    DMA_StreamTx->M0AR = (uint32_t) send;
86
    DMA_StreamTx->CR |= CR_MINC; /* inkrementieren */
87
  }
88
89
90
  DMA_SetCurrDataCounter(DMA_StreamTx, len);
91
  DMA_SetCurrDataCounter(DMA_StreamRx, len);
92
93
94
  /* Enable DMA SPI TX Stream */
95
  DMA_Cmd(DMA_StreamTx, ENABLE);
96
97
  /* Enable DMA SPI RX Stream */
98
  DMA_Cmd(DMA_StreamRx, ENABLE);
99
100
  /* Enable SPI DMA TX Requsts */
101
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
102
103
  /* Enable SPI DMA RX Requsts */
104
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
105
106
  /* Enable the SPI peripheral */
107
  SPI_Cmd(SPIx, ENABLE);
108
109
  /* Waiting the end of Data transfer */
110
  while( DMA_GetFlagStatus(DMA_StreamTx, DMA_FlagTcif_Tx)==RESET );
111
  while( DMA_GetFlagStatus(DMA_StreamRx, DMA_FlagTcif_Rx)==RESET );
112
113
  /* Clear DMA Transfer Complete Flags */
114
  DMA_ClearFlag(DMA_StreamTx, DMA_FlagTcif_Tx);
115
  DMA_ClearFlag(DMA_StreamRx, DMA_FlagTcif_Rx);
116
117
  /* Disable DMA SPI TX Stream */
118
  DMA_Cmd(DMA_StreamTx, DISABLE);
119
120
  /* Disable DMA SPI RX Stream */
121
  DMA_Cmd(DMA_StreamRx, DISABLE);
122
123
  /* Disable SPI DMA TX Requsts */
124
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, DISABLE);
125
126
  /* Disable SPI DMA RX Requsts */
127
  SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, DISABLE);
128
129
  /* Disable the SPI peripheral */
130
  /* Laesst Clock- und Daten-Pins floatend zurueck */
131
  SPI_Cmd(SPIx, DISABLE);
132
}

Die strict aliasing rule hier wohl "nur" deshalb keine Rolle, weil das 
Array per Hardware außerhalb des Betrachtungsbereichs des Compilers 
gefüllt wird.

Was ich mich frage:
 a) Ich habe in einigen Fällen den gleichen Speicherbereich als const 
uint8_t* und uint8_t * übergeben. Kann das Ärger machen?
    Die Unterscheidung ist deshalb drin, weil der Sendepuffer durchaus 
auch aus Literalen im Flash bestehen kann. Dann ist der Empfangsbuffer 
natürlich separat.
 b) Bei den Implementierungen (=Quelltexten) von memmove(), die ich im 
Netz gefunden habe, scheint strict aliasing keine besondere 
Berücksichtigung zu finden. Warum?


Edit: Die Forensoftware weigert sich, die unnoetigen Leerzeilen löschen 
zu lassen.

: Verschoben durch Admin
von Programmierer (Gast)


Lesenswert?

Walter T. schrieb:
> die "strict aliasing rule" besagt ja, dass zwei Zeiger, die einer
> Funktion übergeben werden, vom Compiler als voneinander unabhängig
> betrachtet werden können

Nur wenn die Pointer unterschiedliche Typen haben! Was du meinst ist nur 
der Fall wenn du das "restrict"-Keyword hinzunimmst. "char" (also auch 
"uint8_t") Pointer dürfen als Ausnahme alles Aliasen, weshalb auch 
memcpy, memmove & co funktionieren.

Walter T. schrieb:
> a) Ich habe in einigen Fällen den gleichen Speicherbereich als const
> uint8_t* und uint8_t * übergeben. Kann das Ärger machen?

Nö, das ist gleich doppelt erlaubt:
- Gleicher Typ => dürfen überlappen
- Vom Typ char => dürfen überlappen

Walter T. schrieb:
> b) Bei den Implementierungen (=Quelltexten) von memmove(), die ich im
> Netz gefunden habe, scheint strict aliasing keine besondere
> Berücksichtigung zu finden. Warum?

Dito.

von Programmierer (Gast)


Lesenswert?

Mit anderen Worten: strict-Aliasing wird erst dann zum Problem, wenn man 
"böse" Casts macht, z.B. "int*" nach "short*" o.ä., wobei eben als 
Ausnahme der Cast auf Zeiger auf einen char-Typ erlaubt ist. Solche 
"bösen" Casts sollte man sowieso nie machen (schlechter Stil), wodurch 
sich das Problem in Luft auflöst. Interessanter wird's wenn man das 
"restrict"-Keyword hinzu nimmt.

von Michael (Gast)


Lesenswert?

Programmierer schrieb:
> Mit anderen Worten: strict-Aliasing wird erst dann zum Problem, wenn man
> "böse" Casts macht, z.B. "int*" nach "short*" o.ä., wobei eben als
> Ausnahme der Cast auf Zeiger auf einen char-Typ erlaubt ist.

Auch wenn mir diese Regel bekannt ist, frage ich mich doch, was der 
technische Grund dafür ist. An welcher Stelle im Assembler-Code entsteht 
das Problem?

von Walter T. (nicolas)


Lesenswert?

Programmierer schrieb:
> Nur wenn die Pointer unterschiedliche Typen haben!

Danke für den Hinweis! "strict aliasing" wird nicht unbedingt dadurch 
einfacher, dass es in den Spielregeln (C-Standard) nicht behandelt wird.

Michael schrieb:
> An welcher Stelle im Assembler-Code entsteht
> das Problem?

Ist die Frage ernst oder ein Seitenhieb auf die Hochsprachen-Fraktion?

Wenn ersteres: John Regehr hatte mal etwas Schönes dazu in seinem Blog 
geschrieben: https://blog.regehr.org/archives/1307
Es erlaubt Optimierungen, die sonst nicht möglich sind.

von Programmierer (Gast)


Lesenswert?

Hier ein kleines Beispiel:

https://godbolt.org/z/zj11xvo3r

Ohne Optimierungen gibt der Code 0x0123abab aus, mit Optimierungen 
0x01234567. Bei anderen Compilern/Plattformen kann das Ergebnis 
unterschiedlich sein.

Der Grund ist: Bei eingeschaltetem Optimizer liest der Compiler den Wert 
"*foo" nur ein mal, vor dem ersten printf, aus dem Speicher (Wert 
0x01234567), und behält ihn in einem Prozessor-Register. Weil der 
Zugriff auf das "bar" auf einen anderen Typ stattfindet ("unsigned 
short"), darf der Compiler annehmen, dass dieser den Wert des ersten 
Zugriffs ("unsigned int") nicht beeinflusst, weshalb er den Wert nicht 
erneut ausliest, und beim 2. printf erneut den einmalig gelesenen Wert 
ausgibt. Bei abgeschaltetem Strict Aliasing oder eben bei allgemein 
abgeschalteter Compiler-Optimierung wird diese Optimierung deaktiviert, 
und nach jedem Pointer-Schreiben müssen alle anderen Pointer neu 
ausgelesen werden (ineffizient).

Walter T. schrieb:
> dass es in den Spielregeln (C-Standard) nicht behandelt wird.

Doch, es ist dort explizit und detailliert behandelt, mit allen 
Ausnahmen. Es heißt da nur nicht "strict aliasing". Wenn du 
Standard-Konformen Code schreibst, wird er funktionieren. Das Hadern mit 
Strict Aliasing bzw. das Abschalten mit -fno-strict-aliasing wird nur 
relevant, wenn man fehlerhaften Code schreiben möchte, wie z.B. im 
Linux-Kernel, der nur bei abgeschaltetem Strict Aliasing funktioniert.

von Programmierer (Gast)


Lesenswert?

Walter T. schrieb:
> dass es in den Spielregeln (C-Standard) nicht behandelt wird.

Im aktuellen Draft:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

unter Kapitel 6.5 "Expressions", Absatz 6-7, S. 77, sind die Regeln 
definiert, wie auf Pointer/Union-Elemente zuzugreifen ist. Wenn du dich 
daran hältst, funktioniert alles. Probleme entstehen erst, wenn man 
meint davon abweichen zu müssen.

von Walter T. (nicolas)


Lesenswert?

Programmierer schrieb:
> Im aktuellen Draft unter Kapitel 6.5 "Expressions", Absatz 6-7, S. 77,

Danke! Ich habe schon gesucht, aber war noch nicht über die "Operators" 
hinausgekommen. Vielleicht sollte ich diese 647 Seiten wirklich mal 
lesen, aber die Realität geht ja doch mehr Richtung Strg-F.

: Bearbeitet durch User
von Programmierer (Gast)


Lesenswert?

Walter T. schrieb:
> Vielleicht sollte ich diese 647 Seiten wirklich mal
> lesen,

Naja, das macht keiner so wirklich außer Compiler-Autoren. Gute Bücher 
sind wesentlich hilfreicher zum Lernen der Sprache. Wenn man eine 
definitive Antwort auf ein spezielles Problem braucht kann man ja immer 
noch Strg+F machen...

von Michael (Gast)


Lesenswert?

Walter T. schrieb:
> Wenn ersteres: John Regehr hatte mal etwas Schönes dazu in seinem Blog
> geschrieben: https://blog.regehr.org/archives/1307
> Es erlaubt Optimierungen, die sonst nicht möglich sind.

Natürlich ernst.

Das ist schon ein sehr konstruiertes akademisches Beispiel. Der 
bemängelt beispielsweise OpenSSL, dessen Funktion in unzähligen 
Implementierungen gegeben ist.

Programmierer schrieb:
> Das Hadern mit Strict Aliasing bzw. das Abschalten mit
> -fno-strict-aliasing wird nur relevant, wenn man fehlerhaften Code
> schreiben möchte, wie z.B. im Linux-Kernel, der nur bei abgeschaltetem
> Strict Aliasing funktioniert.

Wieso sollte der Code fehlerhaft sein? Wenn das Ergebnis stimmt, ist der 
Code nicht falsch. Er entspricht allenfalls nicht dem Standard.

Ihr versucht hier mit Gewalt Probleme zu konstruieren, die es in der 
Praxis nicht gibt. Der Code des Threaderstellers wird ebenfalls keine 
Probleme in dieser Hinsicht haben.

von Oliver S. (oliverso)


Lesenswert?

Michael schrieb:
> Wieso sollte der Code fehlerhaft sein? Wenn das Ergebnis stimmt, ist der
> Code nicht falsch. Er entspricht allenfalls nicht dem Standard.

Nun ja, da könnte man anderer Meinung sein.

Egal, hier gibt es was zum Nachlesen zum Thema:

https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8

Oliver

von Walter T. (nicolas)


Lesenswert?

Walter T. schrieb:
> Vielleicht sollte ich diese 647 Seiten...

Hoppla! Jetzt sind es 701 Seite. Also noch einmal 54 Seiten mehr als 
das, was Jörg vor ein paar Wochen als Draft verlinkt hat. Der Text wird 
schneller länger als ich lesen kann!

Michael schrieb:
> Das ist schon ein sehr konstruiertes akademisches Beispiel.

Das sind wohl alle sehr kurzen, prägnanten Beispiele, die in zwei Zeilen 
etwas auf den Punkt bringen sollen.

Michael schrieb:
> Ihr versucht hier mit Gewalt Probleme zu konstruieren, die es in der
> Praxis nicht gibt.

Ich mache ein "Code Review". In Anführungszeichen, weil das bei selbst 
geschriebenem Code eigentlich nicht geht. Da ist es Sinn und Zweck der 
Sache, überargwöhnisch zu sein.

von Programmierer (Gast)


Lesenswert?

Michael schrieb:
> Wieso sollte der Code fehlerhaft sein? Wenn das Ergebnis stimmt, ist der
> Code nicht falsch.

Nein! Das ist eine völlig falsche und gefährliche Sichtweise. 
Insbesondere in C und C++ gibt es sehr viel Code, dessen Ergebnis zwar 
korrekt aussieht, der aber dennoch fehlerhaft ist. Beim Portieren auf 
eine andere Plattform, einen anderen Compiler, Ändern der 
Compiler-Optionen usw. kann dieser Code plötzlich falsche Ergebnisse 
liefern.

>Er entspricht allenfalls nicht dem Standard.

Code, der nicht dem Standard entspricht, ist falsch, da es keinerlei 
Garantie gibt, dass er unter allen Bedingungen (Plattformen, 
Compiler-Versionen/Optionen) das richtige Ergebnis liefert. Das kann 
gerade im Embedded-Bereich schlimme Folgen haben (IIRC ist deswegen eine 
Ariane-Rakete abgestürzt). Die meisten Compiler liefern zusätzliche 
Garantien was funktioniert, aber dann hat man immer noch Probleme beim 
Portieren auf andere Compiler.

Michael schrieb:
> Ihr versucht hier mit Gewalt Probleme zu konstruieren, die es in der
> Praxis nicht gibt.

z.B. der Linux-Kernel ist voll mit solchen Problemen. Wäre er das nicht, 
könnte man ohne -fno-strict-aliasing kompilieren, was die Performance 
verbessern würde.

Michael schrieb:
> Das ist schon ein sehr konstruiertes akademisches Beispiel.

Solche "akademischen Beispiel" sind sehr verbreitet in existierendem 
Code, insbesondere wenn es um Serialisierung und Netzwerkprotokolle 
geht. Hier im Forum wird alle 3 Tage danach gefragt, und es kommen 
sofort 100 Antworten welche die Strict-Aliasing-Rules verletzen, und 
somit genau wie in meinem Beispiel nur bei abgeschalteter Optimierung 
funktionieren. Rein zufällig gibt es auch alle 5 Tage eine Frage "Warum 
funktioniert mein Code nur ohne Optimierungen?". Manche Firmen 
kompilieren nie mit Optimierungen und kaufen lieber leistungsfähigere 
Controller, weil sie es nicht schaffen korrekten Code zu schreiben.

von Walter T. (nicolas)


Lesenswert?

Walter T. schrieb:
> Hoppla! Jetzt sind es 701 Seite. Also noch einmal 54 Seiten mehr als
> das, was Jörg vor ein paar Wochen als Draft verlinkt hat. Der Text wird
> schneller länger als ich lesen kann!

Ich habe mich verguckt. Der Draft vom Dezember 2020 ist 54 Seiten kürzer 
als der oben verlinkte Draft vom April 2011. Es geht also in die 
richtige Richtung. :-)

[Edit]

Beitrag "Re: [gcc,clang] kein Error bei Funktionsaufruf mit falschen Parametern"

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Programmierer schrieb:
> Manche Firmen kompilieren nie mit Optimierungen und kaufen lieber
> leistungsfähigere Controller, weil sie es nicht schaffen korrekten Code
> zu schreiben.

Dein ganzer Beitrag zeugt von einer gänzlich gegensätzlichen Sichtweise 
zwischen uns beiden.

Was nutzt ein Standard, der an der Praxis vorbeigeht? Was nutzt ein 
Compiler, der diesen Standard einhält, aber sich nicht so verhält, wie 
es die Anwender erwarten?

Gerade wenn es um Optimierungen usw. geht, sollte der vorhandene Code, 
wie Linux usw., als Grundlage herhalten und sicherstellen, dass dieser 
damit funktioniert.

Kann der Compiler nicht zweifelsfrei feststellen, dass die 
Speicherbereiche nicht doch identisch sind, darf er nicht so optimieren, 
dass dadurch Fehler bei der Ausführung entstehen können. Das sollte 
eigentlich selbstverständlich sein. Es vom Datentyp des Parameters 
abhängig zu machen ist verrückt. Klar, bei float und int mag es 
konstruiert erscheinen, aber ein int* und ein void* als Parameter 
derselben Funktion können durchaus identisch sein.

Ich kenne die Arbeit in Normgremien selbst, da kommt selten etwas 
brauchbares heraus, Kompromisse dienen fast immer nur dazu, damit keiner 
der Beteiligten einen Gesichtsverlust erleidet...

von Walter T. (nicolas)


Lesenswert?

Michael schrieb:
> Gerade wenn es um Optimierungen usw. geht, sollte der vorhandene Code,
> wie Linux usw., als Grundlage herhalten und sicherstellen, dass dieser
> damit funktioniert.

STOP!

Diese Diskussion ("Hat sich der GCC an den Linix-Kernel oder an den 
C-Standard anzupassen?") hat sehr viele heiße Diskussionen in den 
entsprechenden Feeds verursacht. Hier passt sie nicht hin. Hier geht es 
nur um "strict aliasing" im Kontext "ARM-GCC". Um den IST-Zustand, 
keinen SOLL-Zustand.

: Bearbeitet durch User
von Programmierer (Gast)


Lesenswert?

Michael schrieb:
> Was nutzt ein Standard, der an der Praxis vorbeigeht?

Wo/Wieso tut er das?

Michael schrieb:
> Was nutzt ein
> Compiler, der diesen Standard einhält, aber sich nicht so verhält, wie
> es die Anwender erwarten?

Wo ist klar definiert, was die Anwender erwarten? Im Standard.

Michael schrieb:
> Gerade wenn es um Optimierungen usw. geht, sollte der vorhandene Code,
> wie Linux usw., als Grundlage herhalten und sicherstellen, dass dieser
> damit funktioniert.

So klappt das aber nicht. Wer definiert, welcher Code genau korrekt ist 
und welcher nicht? Findest du, Strict Aliasing sollte aus dem Standard 
entfernt werden, sodass der Linux-Code korrekt wird, aber dafür der 
gesamte C-Code langsamer?

Michael schrieb:
> Kann der Compiler nicht zweifelsfrei feststellen, dass die
> Speicherbereiche nicht doch identisch sind

Das kann er praktisch nie.

Michael schrieb:
> Das sollte
> eigentlich selbstverständlich sein.

Bei FORTRAN ist es genau eben nicht so, da gibt es kein Aliasing, 
weshalb FORTRAN bis heute einen Geschwindigkeitsvorteil hat. Um das in C 
nachzubilden gibt es Strict Aliasing und das "restrict" Keyword.

Michael schrieb:
> aber ein int* und ein void* als Parameter
> derselben Funktion können durchaus identisch sein.

void* kann man eh nicht dereferenzieren, also kein Problem.

Michael schrieb:
> Es vom Datentyp des Parameters
> abhängig zu machen ist verrückt.

Es ist naheliegend, dass Pointer unterschiedlichen Typs nicht auf das 
gleiche zeigen können.

Hast du jetzt ein Problem mit Strict Aliasing im Speziellen oder dem 
C-Standard im Allgemeinen? Wenn du nur Strict Aliasing nicht magst und 
mit dem Geschwindigkeitsnachteil leben kannst (ich höre c-hater schon 
lachen), kannst du gerne mit -fno-strict-aliasing kompilieren.

Wenn du findest, dass der ganze Standard so umgebaut werden sollte dass 
er viel nachlässiger ist und auch kein Undefined Behaviour kennt (was ja 
bis jetzt ebenfalls der Performance zugute kommt), kannst du auch 
einfach Java verwenden, denn da ist es genau so: Code, der das korrekte 
Ergebnis liefert, tut das wahrscheinlich immer und ist korrekt. Wenn 
Multithreading ins Spiel kommt, stimmt das natürlich auch nicht mehr.

von Programmierer (Gast)


Lesenswert?

Walter T. schrieb:
> Hier passt sie nicht hin. Hier geht es
> nur um "strict aliasing" im Kontext "ARM-GCC". Um den IST-Zustand,
> keinen SOLL-Zustand.

Das Ganze ist sowieso weder ARM- noch GCC-spezifisch. Das o.g. Beispiel 
ist amd64, und das ist bei anderen Compilern ganz genauso.

von Michael (Gast)


Lesenswert?

Programmierer schrieb:
> void* kann man eh nicht dereferenzieren, also kein Problem.

Haha. Zum Dereferenzieren brauche ich einen Cast und dann fängt das 
Spiel doch an...

Programmierer schrieb:
> Es ist naheliegend, dass Pointer unterschiedlichen Typs nicht auf das
> gleiche zeigen können.

Sehe ich nicht so. Für den Compiler sind zwei Structs unterschiedlich, 
obwohl sie identisch aufgebaut sind. Und die genannte "Vererbung" (ein 
Struct beginnt mit einem anderen Struct) ist für mich durchaus legitime 
Verwendung.

Programmierer schrieb:
> Wo ist klar definiert, was die Anwender erwarten? Im Standard.

Das ist absurd. Ich habe diesen Standard nicht geschrieben, das ist 
nicht, was ich oder viele andere Anwender erwarten. Das ist das, was das 
Normgremium beschlossen hat.

Die Frage ist, was für den Hersteller des Compilers relevant ist. Es gab 
Firmen, die ihre Kunden zufrieden stellen wollten. Bei GCC hat das heute 
sowieso eine merkwürdige Richtung eingeschlagen...

von Walter T. (nicolas)


Lesenswert?

Meinetwegen. Mein Teil ist eh geklärt. Sollte eine ähnliche 
Fragestellung noch einmal auftauchen, mache ich einen neuen Thread auf. 
Viel Spaß noch!

von Programmierer (Gast)


Lesenswert?

Michael schrieb:
> Haha. Zum Dereferenzieren brauche ich einen Cast und dann fängt das
> Spiel doch an...

Und auf was möchtest du den void* casten, und wieso kannst du das nicht 
anders lösen?

Michael schrieb:
> Für den Compiler sind zwei Structs unterschiedlich,
> obwohl sie identisch aufgebaut sind.

Das stimmt nur halb, es gibt im Kontext von Unions die "common initial 
sequence".

Michael schrieb:
> Und die genannte "Vererbung" (ein
> Struct beginnt mit einem anderen Struct) ist für mich durchaus legitime
> Verwendung.

Das lässt sich aber auch lösen, indem man den "upcast" explizit macht, 
d.h. den Pointer auf das "Basis-Element" übergibt.

Michael schrieb:
> Das ist absurd. Ich habe diesen Standard nicht geschrieben, das ist
> nicht, was ich oder viele andere Anwender erwarten.

Na dann schreibe deinen eigenen Standard und hoffe dass ihn jemand 
implementiert. Oder benutze einfach eine Sprache in der das schon so 
ist.

Michael schrieb:
> Bei GCC hat das heute
> sowieso eine merkwürdige Richtung eingeschlagen...

Wieso, die sind doch sogar so nett und bieten -fno-strict-aliasing an, 
was erwartest du denn noch, dass das standardmäßig an ist?

von Michael (Gast)


Lesenswert?

Programmierer schrieb:
> was erwartest du denn noch, dass das standardmäßig an ist?

Ja, zum Beispiel. "Invasive Optimierungen" sollten nur dann greifen, 
wenn der Anwender weiß, was er tut.

Was ist in der Praxis häufiger vertreten? Genaue Kenntnis über diese 
"Strict Aliasing"-Geschichte? Oder Code, der diese verletzt?

Es bleibt festzustellen, dass es mit älteren Compilern kaum solche 
Fragestellungen gab. C89 funktionierte einwandfrei, heute kommen alle 
paar Jahre neue Versionen der Standards. Das heutige C++ zum Beispiel 
hat keinerlei Ähnlichkeit mehr zu dem, was ich damals kennenlernte in 
den Neunzigern...

von Programmierer (Gast)


Lesenswert?

Michael schrieb:
> Ja, zum Beispiel. "Invasive Optimierungen" sollten nur dann greifen,
> wenn der Anwender weiß, was er tut.

Praktisch alle Optimierungen sind invasiv auf die eine oder andere Art, 
und die sind auch nur an wenn man -O übergibt. Was jetzt standardmäßig 
an oder aus ist ist Haarspalterei. Ich finde es gefährlich, 
standardmäßig nicht-standard-konformen Code durchzuwinken.

Michael schrieb:
> Was ist in der Praxis häufiger vertreten? Genaue Kenntnis über diese
> "Strict Aliasing"-Geschichte? Oder Code, der diese verletzt?

C ist eine Systems Programming Sprache, um effizienten Low-Level-Code zu 
implementieren. Es geht nicht darum, diese für Anfänger einfach zu 
machen. C ist ein kompliziertes aber mächtiges Werkzeug, das man 
bedienen können muss. Für alles andere gibt es andere Sprachen. C auf 
Kosten der Performance zu vereinfachen wäre so wie ein Formel-1 Auto mit 
Kofferraum und Klimaanlage auszustatten.

Michael schrieb:
> Es bleibt festzustellen, dass es mit älteren Compilern kaum solche
> Fragestellungen gab.

Dafür waren die auch langsamer.

Michael schrieb:
> C89 funktionierte einwandfrei

C89 hatte Strict Aliasing auch schon, das war schon immer Teil der 
Sprache! Nur weil die uralten Compiler - bzw. die, die du verwendet hast 
- das nicht ausnutzen konnten...

von Oliver S. (oliverso)


Lesenswert?

Michael schrieb:
> Es bleibt festzustellen, dass es mit älteren Compilern kaum solche
> Fragestellungen gab. C89 funktionierte einwandfrei, heute kommen alle
> paar Jahre neue Versionen der Standards.

K&R, Ansi/C90, C99, C11, C18, ...

Stimmt, das geht so irrsinnig schnell voran, da kann man wirklich kaum 
Schritt halten. Da ist ja noch nicht mal die Tinte trocken, schon gibt 
einen neuen Standard ;)

Michael schrieb:
> Das heutige C++ zum Beispiel
> hat keinerlei Ähnlichkeit mehr zu dem, was ich damals kennenlernte in
> den Neunzigern...

Bisher war das alles immer abwärtskompatibel, und du kannst dem 
Compilern sagen, welchen Standard du gerne hättest. Der C++-Standard 
hindert dich nicht daran, C++-Code so zu schreiben, wie du es 
(kennen-)gelernt hast.

Oliver

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Programmierer schrieb:
> Es geht nicht darum, diese für Anfänger einfach zu machen.

Ich bezweifle, dass der Linux-Kernel von Anfängern entwickelt wird.

Oliver S. schrieb:
> Der C++-Standard hindert dich nicht daran, C++-Code so zu schreiben, wie
> du es (kennen-)gelernt hast.

Das ist korrekt. Aber der Code, mit dem man heute konfrontiert wird, 
nutzt das teilweise intensiv. Glücklicherweise ist in meinem Unternehmen 
mittlerweile alles ausdrücklich verboten, was nach C++03 kam.

Das geht einfach in die falsche Richtung, aus meiner Sicht. Für Viele 
war C++ im Prinzip "C mit Klassen", also als solches wie es auch 
erfunden wurde. Manche wollen aber mit dem aktuellen C++ Java und C# 
usw. noch überholen...

von Programmierer (Gast)


Lesenswert?

Michael schrieb:
> Ich bezweifle, dass der Linux-Kernel von Anfängern entwickelt wird.

Eine Menge Treiber kommen von Firmen, die nicht immer die Kompetentesten 
sind... Aber die Strict-Aliasing-Entscheidung kommt von Linus Torvalds, 
und der hat sowieso spezielle Ansichten. Wahrscheinlich ist die Codebase 
einfach zu groß um es umzustellen, schließlich kompiliert der 
Linux-Kernel auch nur mit dem GCC mit ganz bestimmten Einstellungen.

Michael schrieb:
> Glücklicherweise ist in meinem Unternehmen
> mittlerweile alles ausdrücklich verboten, was nach C++03 kam.

Gibt es dafür einen technischen Grund, oder ist nur keine Zeit zum 
Lernen da? Schließlich kann man mit dem neuen C++ effizienteren, 
kompakteren, wartbareren Code schreiben.

Michael schrieb:
> Manche wollen aber mit dem aktuellen C++ Java und C#
> usw. noch überholen...

Klar, C++ hat schon immer Dinge ermöglicht die in anderen Sprachen nicht 
gehen. So kann man z.B. mit dem "neuen" Speichermodell (C++11) sehr 
effizient Multithreading nutzen, was in den anderen Sprachen zwar 
einfacher, aber auch weniger effizient ist. C++03 unterstützt offiziell 
überhaupt kein Multithreading, weshalb man auf nicht-portable 
Plattform-Spezifische Lösungen zurückgreifen muss - IMO nicht sehr 
erstrebenswert.

von PittyJ (Gast)


Lesenswert?

Programmierer schrieb:
>
> Klar, C++ hat schon immer Dinge ermöglicht die in anderen Sprachen nicht
> gehen. So kann man z.B. mit dem "neuen" Speichermodell (C++11) sehr
> effizient Multithreading nutzen, was in den anderen Sprachen zwar
> einfacher, aber auch weniger effizient ist. C++03 unterstützt offiziell
> überhaupt kein Multithreading, weshalb man auf nicht-portable
> Plattform-Spezifische Lösungen zurückgreifen muss - IMO nicht sehr
> erstrebenswert.

Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und 
32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.
Da ist nun mal kein Betriebsystem mit Threads darunter und auch new 
Operatoren kosten extrem. Nichts mit Maps und Vektoren, die permanent 
reallozieren. Da ist dann sofort der Speicher verhunzt.

Ich bleibe schön bei 'altem C++' weil ich damit auf Embedded Prozessoren 
arbeiten kann. Die neuen Features ignoriere ich, weil die nicht portabel 
sind.

von mh (Gast)


Lesenswert?

Programmierer schrieb:
> Wahrscheinlich ist die Codebase einfach zu groß um es umzustellen, schließlich 
kompiliert der
> Linux-Kernel auch nur mit dem GCC mit ganz bestimmten Einstellungen.
Das funktioniert als Ausrede für die Inkompatibilitäten mit dem 
C-Standard im existierenden Code. Aber mit jeder Zeile die neu 
hinzukommt oder geändert wird, könnte man sich an die Regeln halten. 
Dann würde der Unterschied mit der Zeit immer kleiner, statt immer 
größer.

von mh (Gast)


Lesenswert?

PittyJ schrieb:
> Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und
> 32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.
> Da ist nun mal kein Betriebsystem mit Threads darunter und auch new
> Operatoren kosten extrem. Nichts mit Maps und Vektoren, die permanent
> reallozieren. Da ist dann sofort der Speicher verhunzt.
>
> Ich bleibe schön bei 'altem C++' weil ich damit auf Embedded Prozessoren
> arbeiten kann. Die neuen Features ignoriere ich, weil die nicht portabel
> sind.

Und was ist mit all den Features, die keinen zusätlichen Ram oder Flash 
benötigen, sondern evtl. zu einer Ersparnis führen?

von Programmierer (Gast)


Lesenswert?

PittyJ schrieb:
> Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und
> 32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.

PittyJ schrieb:
> Die neuen Features ignoriere ich, weil die nicht portabel
> sind.

Variadische templates, constexpr, <cstdint> & co kosten nichts an 
Speicher und eigenen sich super für Mikrocontroller. Die Atomics, welche 
mit C++11 bzw. C11 eingeführt wurden, funktionieren auch für 
Mainloop<->ISR Synchronisation ohne Betriebssystem und passen genau auf 
die Atomic-Instruktionen von ARM's, die man sonst ohne Inline Assembly 
nicht nutzen könnte.

von Walter T. (nicolas)


Lesenswert?

Ich fürchte, ihr werdet die Diskussion zu keinem fruchtbaren Ergebnis 
bringen. Beide Seiten haben gute Gründe. Und die Diskussionen in den 
Mailinglisten und Feeds dazu sind ewig lang. Und immer noch nicht 
fertig.

Für die Besitzstandswahrer ist der Quelltext das Tafelsilber, das nicht 
durch neue Compilervarianten beeinträchtigt werden sollte.

Für die Verbesserer ist es wichtiger, neben den älteren neueren 
Anforderungen gerecht zu werden.

Meine persönliche Meinung ist es ja, dass Quelltext ein Investitionsgut 
ist, dass über 7 Jahre abgeschrieben gehört. Und genau wie man auch 
Maschinen und Gerätschaften weit über die Abschreibungsperiode hinaus 
betreiben kann, ist man auch hier dafür selbst verantwortlich, sie am 
Laufen zu halten und ggf. zu warten oder warten zu lassen.

Bei vielen Maschinen ist es sogar so, dass Umbauten auch immer 
automatisch die Pflicht beinhalten, auch aktuelle (Sicherheits-) 
Standards einzuhalten. Aber so weit würde ich bei Quelltext nicht gehen 
wollen.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Michael schrieb:
> Glücklicherweise ist in meinem Unternehmen
> mittlerweile alles ausdrücklich verboten, was nach C++03 kam.

Jeder ist seines Glückes Schmied...

Oliver

von aliasing (Gast)


Lesenswert?

Programmierer schrieb:
> PittyJ schrieb:
>> Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und
>> 32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.
>
> PittyJ schrieb:
>> Die neuen Features ignoriere ich, weil die nicht portabel
>> sind.
>
> Variadische templates, constexpr, <cstdint> & co kosten nichts an
> Speicher und eigenen sich super für Mikrocontroller. Die Atomics, welche
> mit C++11 bzw. C11 eingeführt wurden, funktionieren auch für
> Mainloop<->ISR Synchronisation ohne Betriebssystem und passen genau auf
> die Atomic-Instruktionen von ARM's, die man sonst ohne Inline Assembly
> nicht nutzen könnte.

oder auch std::span, ist ein super Ding!
Gibt es auf github als freie Implementierung, das funktioniert dann auch 
mit älteren Compilern bis der eigene Compiler C++20 kann.

C++ ist genauso schlank und effizient wie C - you only pay for what you 
use.
Gibt aber immer noobs die objektoriente Programmierung in C++ mit 
Interfaces und Vererbung mit einzelnen Funktionen in C vergleichen.

Auch in C programmiert man ojektorientiert und das kostet dann genauso 
viel.

von Rolf M. (rmagnus)


Lesenswert?

Programmierer schrieb:
> Variadische templates, constexpr, <cstdint> & co kosten nichts an
> Speicher und eigenen sich super für Mikrocontroller.

Oder schon so einfache Erleichterungen der Schreibarbeit wie range-based 
for oder auto. Und auch lambdas können hilfreich sein. Damit ist ein 
std::sort effizienter als ein qsort.

Antwort schreiben

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

Wichtige Regeln - erst lesen, dann posten!

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

Formatierung (mehr Informationen...)

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




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

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