Forum: Compiler & IDEs Fragen zu MISRA


von Sich am Riemen reißender (Gast)


Lesenswert?

MISRA
In "Gemeinsames Subset der MISRA C Guidelines" fand ich folgende 
Aussagen:

The basic type of char, int, short, long, float and double should not be 
used, but specific-
length equivalents should be typedef'd for the specific compiler, and 
these type names
used in the code.
Das würde vielleicht erklären, warum mir immer wieder die Datentypen 
int8_t oder uint32_t über den Weg laufen - so richtig kompatibel zu int 
sind die erfahrungsgemäß ja nicht. Aber was hat's damit allgemein auf 
sich?


The library functions atof, atoi and atol from library <stdlib.h> shall 
not be used.
Warum? Zu gefährlich?

The time handling functions of library <time.h> shall not be used
Codeabhängig wg. Interrupts?

von Klaus W. (mfgkw)


Lesenswert?

Sich am Riemen reißender schrieb:
> MISRA
> In "Gemeinsames Subset der MISRA C Guidelines" fand ich folgende
> Aussagen:
>
> The basic type of char, int, short, long, float and double should not be
> used, but specific-
> length equivalents should be typedef'd for the specific compiler, and
> these type names
> used in the code.
> Das würde vielleicht erklären, warum mir immer wieder die Datentypen
> int8_t oder uint32_t über den Weg laufen - so richtig kompatibel zu int
> sind die erfahrungsgemäß ja nicht. Aber was hat's damit allgemein auf
> sich?

Weil je nach System die Typen unterschiedliche Wertebereiche haben, kann 
ein Programm auf einem System funktionieren, und auf  einem anderen 
scheitern (z.B. wenn man int für Werte nimmt, die mehr als 2 Byte 
benötigen)

>
> The library functions atof, atoi and atol from library <stdlib.h> shall
> not be used.
> Warum? Zu gefährlich?

Weil sie die ach so bösen int, long und float nehmen.

Sich am Riemen reißender schrieb:
> The time handling functions of library <time.h> shall not be used
> Codeabhängig wg. Interrupts?

Alles böse!

(Ich mag keine bornierten Ideologen, deshalb auch kein MISRA.)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Gibt es im MISRA-Dokument kein "Rationale"-Kapitel, das solche Fragen 
beantwortet?

von Stefan R. (srand)


Lesenswert?

Sich am Riemen reißender schrieb:
> The basic type of char, int, short, long, float and double should not be
> used, but specific-

Für char finde ich das ausgesprochen albern. Insbesondere da die Länge 
da eben nicht systemabhängig ist. Ein char ist ein Byte. Fertig.

(Vermutlich geht es denen um die systemabhängige Definition des char als 
unsigned oder signed, aber wenn das im Code einen Unterschied macht, 
dann sollte man es explizit deklarieren und nicht einfach char nehmen.)

von c2000 (Gast)


Lesenswert?

Mit nichten! Ein char kann auch z.B. 16 bit lang sein. Z.B. beim C2000 
ist ein char immer 16 bit!

von Sven P. (Gast)


Lesenswert?

Sich am Riemen reißender schrieb:
> The basic type of char, int, short, long, float and double should not be
> used, but specific-
> length equivalents should be typedef'd for the specific compiler, and
> these type names
> used in the code.
> Das würde vielleicht erklären, warum mir immer wieder die Datentypen
> int8_t oder uint32_t über den Weg laufen - so richtig kompatibel zu int
> sind die erfahrungsgemäß ja nicht. Aber was hat's damit allgemein auf
> sich?
Gegenfrage: Welchen Datentyp nimmst du denn, wenn du Werte zwischen 
-40000 und +40000 speichern möchtest?


> The library functions atof, atoi and atol from library <stdlib.h> shall
> not be used.
> Warum? Zu gefährlich?
Nein, eher überholt. Besser sind strtol/strtoul/strtof, mit denen kann 
man auch fehlerhafte Strings erkennen. Das geht mit atoi etc. nicht.

> The time handling functions of library <time.h> shall not be used
> Codeabhängig wg. Interrupts?
Da sind viele Funktionen bei, die nicht eintrittsinvariant sind. asctime 
etc., die liefern den formatierten String in einem statischen 
Stringpuffer zurück und das verträgt sich prinzipiell nicht so gut mit 
Nebenläufigkeit.

von Sven P. (Gast)


Lesenswert?

Stefan Rand schrieb:
> Sich am Riemen reißender schrieb:
>> The basic type of char, int, short, long, float and double should not be
>> used, but specific-
>
> Für char finde ich das ausgesprochen albern. Insbesondere da die Länge
> da eben nicht systemabhängig ist. Ein char ist ein Byte. Fertig.
Das ist richtig. Aber ein Byte ist nicht immer ein Oktett. C99 
garantiert aber, dass alle anderen Typen stets Vielfache Größen von 
'char' sind und dass ein 'char' mindestens 8 Bit hat.

von Matthias H. (experimentator)


Lesenswert?

Sich am Riemen reißender schrieb:
> MISRA
> In "Gemeinsames Subset der MISRA C Guidelines" fand ich folgende
> Aussagen:
>
> The basic type of char, int, short, long, float and double should not be
> used, but specific-
> length equivalents should be typedef'd for the specific compiler, and
> these type names
> used in the code.
> Das würde vielleicht erklären, warum mir immer wieder die Datentypen
> int8_t oder uint32_t über den Weg laufen - so richtig kompatibel zu int
> sind die erfahrungsgemäß ja nicht. Aber was hat's damit allgemein auf
> sich?

Ganz einfach: C definiert nicht den genauen Wertebereich, den diese 
einfachen Datentypen haben, sondern der Compilerhersteller sucht sich 
das in Abhängigkeit von der Zielplattform aus. Es könnte durchaus sein, 
daß sogar auf der gleichen Plattform je nach Compiler ein int mal 16 und 
mal 32 Bits hat und so weiter.

> The library functions atof, atoi and atol from library <stdlib.h> shall
> not be used.
> Warum? Zu gefährlich?

Ich kann nur raten, aber wahrscheinlich aus oben genanntem Grund. char 
(das a in den Funktionen!), float, int und long sind ja 
plattformspezifische Typen. Wenn man sich eigene Typen per "typedef" 
schafft, dann weiß man nicht, auf welche nativen Typen diese auf jeder 
Plattform abgebildet werden, sodaß es zu unerwarteten Fehlfunktionen 
kommen könnte.

> The time handling functions of library <time.h> shall not be used
> Codeabhängig wg. Interrupts?

Möglicherweise ist nicht einmal garantiert, daß die Plattform eine Uhr 
hat, die für sinnvolle Werte bei Funktionen wie time() sorgt?

von Sich am Riemen reißender (Gast)


Lesenswert?

Smarter every day. Danke für die Hilfe.


>Gibt es im MISRA-Dokument kein "Rationale"-Kapitel, das solche Fragen
>beantwortet?
Ich hab nur das benutzt was ich bei Wiki finden konnte, ein 
vollständiges Originaldokument fand ich nicht.



>Weil je nach System die Typen unterschiedliche Wertebereiche haben, kann
>ein Programm auf einem System funktionieren, und auf einem anderen
>scheitern
Ahh! Das würde dann zB. bedeuten, daß eine int-Zahl, deklariert mit 
int32_t immer, unabhängig vom Zielsystem, 32bit hat. Wunderbar.



Wenn ich jetzt noch wüßte, was
Autor: Sven P. (haku)
mit
>eintrittsinvariant
meinte...
ist der Regentag gerettet.

von Sven P. (Gast)


Lesenswert?

Sich am Riemen reißender schrieb:
> Wenn ich jetzt noch wüßte, was
> Autor: Sven P. (haku)
> mit
>>eintrittsinvariant
> meinte...
> ist der Regentag gerettet.
Neusprech: 'reentrant'. Die Funktionen benutzen einen statischen Puffer. 
Wenn du die Funktion aus dem Programm aufrufst und dann kommt ein 
Interrupt, der dieselbe Funktion seinerseits aufruft, überschreiben die 
beiden Aufrufe sich gegenseitig den (gemeinsamen, da statischen) Puffer.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Sven P. schrieb:
> Die Funktionen benutzen einen statischen Puffer.

Wobei das m.W. nur die Funktionen asctime und ctime (die auf asctime 
aufbaut) betrifft. Beide sind sowieso deprecated, und man sollte 
stattdessen strftime benutzen. Somit würde ich es verstehen, wenn MISRA 
asctime und ctime verböte, aber warum sind gleich alle Funktionen aus 
time.h böse?


Sich am Riemen reißender schrieb:
>>Gibt es im MISRA-Dokument kein "Rationale"-Kapitel, das solche Fragen
>>beantwortet?
> Ich hab nur das benutzt was ich bei Wiki finden konnte, ein
> vollständiges Originaldokument fand ich nicht.

Das Originaldokument gibt es nur für Geld. Wenn du MISRA benutzen 
musst, sollte derjenige, der dir das vorschreibt (bspw. dein 
Arbeitgeber), dieses Dokument haben. Wenn du MISRA nicht benutzen musst, 
dann mach einfach einen weiten Bogen drumherum :)

Ich bezweifle allerdings, dass in dem Dokument tatsächlich Begründungen 
für die Regeln enthalten sind, und wenn doch, dürften viele von ihnen 
überholt sein. Viele der Regeln stammen noch aus Zeiten, wo C-Compiler 
noch nicht in der Lage waren, gefährliche Programmkonstrukte selber zu 
erkennen und als Warnung auszugeben. Um die MISRA-Regeln einfach zu 
halten, sind sie oft allgemeiner gehalten als wirklich nötig und 
verbieten damit auch Konstrukte, die eigentlich völlig ungefährlich 
sind.

von Rolf Magnus (Gast)


Lesenswert?

Stefan Rand schrieb:
> Sich am Riemen reißender schrieb:
>> The basic type of char, int, short, long, float and double should not be
>> used, but specific-
>
> Für char finde ich das ausgesprochen albern. Insbesondere da die Länge
> da eben nicht systemabhängig ist. Ein char ist ein Byte. Fertig.
>
> (Vermutlich geht es denen um die systemabhängige Definition des char als
> unsigned oder signed, aber wenn das im Code einen Unterschied macht,
> dann sollte man es explizit deklarieren und nicht einfach char nehmen.)

Eigentlich würde das doch auch implizit bedeuten, daß man sämtliche 
Funktionen, die mit Arrays aus char arbeiten, also z.B. alle 
Stringfunktionen oder auch fopen() nicht verwenden darf, denn man müßte 
ihnen ja ein Array aus char übergeben.

Sven P. schrieb:
> Sich am Riemen reißender schrieb:
>> Wenn ich jetzt noch wüßte, was
>> Autor: Sven P. (haku)
>> mit
>>>eintrittsinvariant
>> meinte...
>> ist der Regentag gerettet.
> Neusprech: 'reentrant'. Die Funktionen benutzen einen statischen Puffer.
> Wenn du die Funktion aus dem Programm aufrufst und dann kommt ein
> Interrupt, der dieselbe Funktion seinerseits aufruft, überschreiben die
> beiden Aufrufe sich gegenseitig den (gemeinsamen, da statischen) Puffer.

Ich hätte da eher verboten, solche Funktionen überhaupt aus einer ISR 
heraus aufzurufen.

von Stefan R. (srand)


Lesenswert?

c2000 schrieb:
> Mit nichten! Ein char kann auch z.B. 16 bit lang sein. Z.B. beim C2000
> ist ein char immer 16 bit!

Ja und? Ist trotzdem ein Byte.

von Stefan R. (srand)


Lesenswert?

Sven P. schrieb:
> Das ist richtig. Aber ein Byte ist nicht immer ein Oktett.

Macht ja nix. Wenn man ein Byte braucht (für memcpy und Konsorten), dann 
nimmt man char, ansonsten halt uint8_t und sowas.

von Rolf Magnus (Gast)


Lesenswert?

Stefan Rand schrieb:
> c2000 schrieb:
>> Mit nichten! Ein char kann auch z.B. 16 bit lang sein. Z.B. beim C2000
>> ist ein char immer 16 bit!
>
> Ja und? Ist trotzdem ein Byte.

Ja, aber die Länge ist eben doch systemabhängig. Das ist nicht soviel 
anders als bei int. char ist eben mindestens 8 Bit groß, kann aber auch 
größer sein, int ist mindestens 16 Bit groß, kann aber auch größer sein. 
Der einzige Unterschied ist, daß sizeof(char) immer 1 ist, aber das 
hilft dir auch nicht viel.

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


Lesenswert?

Yalu X. schrieb:
> Ich bezweifle allerdings, dass in dem Dokument tatsächlich Begründungen
> für die Regeln enthalten sind

Da unterschätzt du MISRA allerdings.

“The time handling functions of library <time.h> shall not be used.

Includes time, strftime.  This library is associated with clock
times.  Various aspects are implementation dependent or unspecified,
such as the formats of times.  If any of the facilities of time.h
are used then the exact implementation for the compiler being used
must be determined and a deviation raised.”

von Yalu X. (yalu) (Moderator)


Lesenswert?

Jörg Wunsch schrieb:
> Da unterschätzt du MISRA allerdings.

Ja, ich habe mich inzwischen auch etwas näher darüber informiert :)

Bei der Diskussion hier sollte man sich der folgenden Punkte bewusst
sein:

- Es gibt mehrere Versionen von MISRA-C: von 1998 (C90), 2004 (C90) und
  2012 (C99/C11) und zusätzlich eine Version von MISRA-C++ von 2008.
  Einige Widersprüche und Unklarheiten der früherensten Version sind in
  späteren Versionen behoben worden.

- Die meisten der aufgeführten Regeln sind "required", einige aber auch
  nur "advisory". Man kann den Unterschied im Regeltext an den Wörtern
  "shall" (required) und "should" (advisory) erkennen.

Die Regel, dass für die Basisdatentypen char, short, int usw. Typedefs
verwendet werden sollen, ist advisory und bezieht und bezieht sich seit
MISRA-C:2004 ausdrücklich auf numerische Datentypen. Der Typ char darf
für Zeichen verwendet werden, jedoch ausschließlich für diese. Damit ist
die Verwendung der Funktionen aus string.h legal. Es wird allerdings
empfohlen, char in char_t typezudefen.

von Guest (Gast)


Lesenswert?

Stefan Rand schrieb:
> Für char finde ich das ausgesprochen albern. Insbesondere da die Länge
> da eben nicht systemabhängig ist. Ein char ist ein Byte. Fertig.

Schön wärs ;-). Ich hätte es vorher auch nicht geglaubt, aber ich hatte 
letztens einen DSP in den Fingern dessen Compiler für einen char 16Bit 
benutzt hat.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Guest schrieb:
> Schön wärs ;-). Ich hätte es vorher auch nicht geglaubt, aber ich hatte
> letztens einen DSP in den Fingern dessen Compiler für einen char 16Bit
> benutzt hat.

Ja, aber nach der klassischen Definition ist ein Byte diejenige 
Informationseinheit, in der ein Computer ein einzelnes Zeichen 
speichert.
Auch nach dem C-Standard belegt ein char per definitionem exakt 1 Byte. 
Damit ist auf deinem DSP ein Byte eben 16 Bit groß, die Größe eines char 
aber immer noch 1 Byte. Auf dem TMS320C30 ist sogar ein double nur 1 
Byte groß.

von Guest (Gast)


Lesenswert?

Yalu X. schrieb:
> Damit ist auf deinem DSP ein Byte eben 16 Bit groß, die Größe eines char
> aber immer noch 1 Byte.

Nö, ein char belegt tatsächlich bei dem Ding 2 Byte.
Ist aber auch tatsächlich ein ganz perverses Vieh, die Addressieung ist 
auch ein wenig ungewöhnlich, weil sich hinter jeder Speicheradresse 
nicht ein Byte sondern ein 16Bit Wert verbirgt. Klingt komisch ist aber 
so ;-). Auf ein einzelnes Byte kann also gar nicht direkt zugegriffen 
werden.

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


Lesenswert?

Guest schrieb:
> Nö, ein char belegt tatsächlich bei dem Ding 2 Byte.

Nein.  Per definitionem ist ein Zeichen ein Byte, als kleinste
adressierbare Einheit.  In ähnlicher Form steht das auch im
C-Standard drin; die Anzahl der Bits ist dabei ausdrücklich als
implementierungsabhängig offen gelassen.

Internationale Standards benutzen, wenn sie eine Einheit von 8 Bits
meinen, daher auch den Begriff „Oktett“ (englisch “octet”).

von Guest (Gast)


Lesenswert?

Jörg Wunsch schrieb:
>> Nö, ein char belegt tatsächlich bei dem Ding 2 Byte.
>
> Nein.

Ich glaube wir reden gerade ein bisschen aneinander vorbei ;-).
Ich verstehe aber schon was du meinst.

Ich hätte wohl besser sagen sollen, das ein char bei dem DSP 16Bit 
belegt, was dann von mir aus ein "Byte" ist.

von Karl H. (kbuchegg)


Lesenswert?

Guest schrieb:

> Ich hätte wohl besser sagen sollen, das ein char bei dem DSP 16Bit
> belegt, was dann von mir aus ein "Byte" ist.

Exakt.
C definiert sich sein eigenes 'Byte', das zwar meistens, aber nicht 
notwendigerweise mit der üblichen Definition einer 8-Bit Einheit 
identisch ist.

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


Lesenswert?

Guest schrieb:
> was dann von mir aus ein "Byte" ist.

Wenn du mal zu Wikipedia schaust, wirst du aber merken, dass du mit
deiner Definition eines Bytes relativ allein dastehst.

von Guest (Gast)


Lesenswert?

Häh? Ich habe dir doch recht gegeben und eingesehen, das ich deine 
Antwort missverstanden hatte.

Wenn man halt jeden Tag damit zu tun das ein Byte 8Bit sind muss man 
sich halt erstmal umgewöhnen ;-).

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


Lesenswert?

Guest schrieb:
> Häh? Ich habe dir doch recht gegeben und eingesehen, das ich deine
> Antwort missverstanden hatte.

Sorry, nun hatte ich deine Antwort wohl auch noch missverstanden. ;-)

Aber ich gebe dir völlig Recht, dass man sich an den Gedanken, dass
ein Byte eben manchmal nicht genau 8 Bits hat, wirklich erstmal
gewöhnen muss.

von Falk B. (falk)


Lesenswert?

@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Nein.  Per definitionem ist ein Zeichen ein Byte, als kleinste
>adressierbare Einheit.  In ähnlicher Form steht das auch im
>C-Standard drin; die Anzahl der Bits ist dabei ausdrücklich als
>implementierungsabhängig offen gelassen.

Das ist einer von vielen Gründen, warum ich kein Softwerker bin. Die 
ewige Variabilität elementarster Dinge gehr mir ganz schön auf den Keks. 
Klingt fast so, als hätten Anwälte den C-Standard geschrieben :-(

von Yalu X. (yalu) (Moderator)


Lesenswert?

Falk Brunner schrieb:
> Das ist einer von vielen Gründen, warum ich kein Softwerker bin.

Ist das bei den Hardwerkern etwa anders?

> Die ewige Variabilität elementarster Dinge gehr mir ganz schön auf den
> Keks.

Das Byte ist nicht elementar. Elementar ist das Bit ;-)

> Klingt fast so, als hätten Anwälte den C-Standard geschrieben :-(

Der C-Standard ist bezüglich der Verwendung des Begriffs "Byte" in sich
konsistent. Viel mehr kann man nicht verlangen.

von (prx) A. K. (prx)


Lesenswert?

Ich könnte mir freilich vorstellen, dass man bei einer Architektur, 
deren chars 16 Bits haben, mit (u)int8_t nicht glücklich wird.

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> Das ist einer von vielen Gründen, warum ich kein Softwerker bin. Die
> ewige Variabilität elementarster Dinge gehr mir ganz schön auf den Keks.

Dann pass lieber auf, dass du dich in der Hardware nicht zu sehr den 
elementarsten Dingen näherst, sondern lieber im etwas weniger 
elementaren verbleibst. ;-)

> Klingt fast so, als hätten Anwälte den C-Standard geschrieben :-(

Gezwungenermassen werden Standards gern etwas formal. Der ursprüngliche 
K&R liess in dieser Hinsicht deutlich zu wünschen übrig. Folge: Er galt 
bald als unpräzise.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Das Byte ist nicht elementar.

Als Basis der Adressierbarkeit schon, da in C kein Konzept für 
Bitadressierung existiert.

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:
> Aber ich gebe dir völlig Recht, dass man sich an den Gedanken, dass
> ein Byte eben manchmal nicht genau 8 Bits hat, wirklich erstmal
> gewöhnen muss.

Im Grunde ist das ein ganz alter Hut. Erst seit sich fast die gesamte 
Computerwelt auf 8-Bit Bytes geeinigt hat und nur DSPs Ausnahmen bilden, 
ist das zur Selbstverständlichkeit geworden. Davor war bei vielen 
Maschinen noch nicht einmal eindeutig, wie breit ein Zeichen ist. Weil 
auf der gleichen Maschine im rein wissenschaftlichen Kontext gerne 6 
Bits verwendet wurden, in anderem Kontext für einen grösseren 
Zeichenumfang aber 8 oder 9 Bits. Und keins von beiden direkt 
adressierbar war, weil die Maschine nur Halb- oder Ganzworte direkt 
adressierte.

Und wenn eine Maschine doch sowas wie Bytes adressieren konnte, dann 
konnte es sein, dass die Adresse ein anderes Format besass als normale 
Wortadressen. Also eine Konvertierung von Wort- zu Byteadresse eine 
echte Rechenoperation darstellt (das gibts auch heute noch: MaxQ2000).

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


Lesenswert?

A. K. schrieb:
> Ich könnte mir freilich vorstellen, dass man bei einer Architektur,
> deren chars 16 Bits haben, mit (u)int8_t nicht glücklich wird.

Nun, der Punkt dabei ist ja genau dieser: (u)int8_t existiert auf
einer derartigen Architektur schlicht nicht, und ein entsprechendes
Programm lässt sich nicht compilieren.

Ist ja allemal viel besser als ein Programm, welches implizit annimmt,
dass "unsigned char" 8 Bits repräsentiert, und dann erst irgendwann
später "baden geht".

von Falk B. (falk)


Lesenswert?

@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Ist ja allemal viel besser als ein Programm, welches implizit annimmt,
>dass "unsigned char" 8 Bits repräsentiert, und dann erst irgendwann
>später "baden geht".

Die Logik erschließt sich mir nicht. Welcher (C)-Programmierer geht denn 
NICHT davon aus, dass char 8 Bit hat?

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> Die Logik erschließt sich mir nicht. Welcher (C)-Programmierer geht denn
> NICHT davon aus, dass char 8 Bit hat?

DSP-Programmierer? Allerdings scheint POSIX CHAR_BIT auf exakt 8 Bits 
festzulegen, so dass man wohl nicht beides haben kann - jene DSPs und 
POSIX.

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


Lesenswert?

Falk Brunner schrieb:
> Welcher (C)-Programmierer geht denn NICHT davon aus, dass char 8 Bit
> hat?

Jemand, der den Standard ernst nimmt und sich bei dieser Annahme der
nicht strikten Konformität seiner Applikation bewusst ist.

Seit C99 gibt's ja nun auch keinerlei Grund mehr, für solche Fälle
den Typ “char” zu benutzen: wer eine kleine Ganzzahl mit exakt 8 Bits
benötigt, nehme halt “int8_t” oder “uint8_t”; “char” bleibt dann einfach
dem vorbehalten, wofür es ursprünglich mal konzipiert war: ein Zeichen
für die Ein-/Ausgabe aufzunehmen (einschließlich all der 
str*-Funktionen). Für diesen Zweck ist es auch völlig belanglos, ob das 
“char” nun
vorzeichenbehaftet ist oder nicht.

Wer eine kleine Ganzzahl mit mindestens 8 Bits benötigt, hat die
Wahl zwischen “[u]int_fast8_t” oder “[u]int_least8_t”, je nachdem, ob
ihm die Geschwindigkeit oder das Platzsparen wichtiger ist.  Damit kann
man relativ portabel ausdrücken, dass zwar 8 Bits genügen für den
Zweck, aber (uint_fast8_t) eben auf einem ARM der Datentyp auch ruhig
größer sein darf (weil es schneller geht so), oder aber (uint_least8_t)
eine Umgebung wie die genannten DSPs, die keinen 8-Bit-Typ besitzt,
eben dann einen größeren wählen darf.

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>> Welcher (C)-Programmierer geht denn NICHT davon aus, dass char 8 Bit
>> hat?

>Jemand, der den Standard ernst nimmt und sich bei dieser Annahme der
>nicht strikten Konformität seiner Applikation bewusst ist.

Gibt solche Leute im realen Leben? ;-)

>Seit C99 gibt's ja nun auch keinerlei Grund mehr, für solche Fälle
>den Typ “char” zu benutzen: wer eine kleine Ganzzahl mit exakt 8 Bits
>benötigt, nehme halt “int8_t” oder “uint8_t”; “char” bleibt dann einfach
>dem vorbehalten, wofür es ursprünglich mal konzipiert war: ein Zeichen
>für die Ein-/Ausgabe aufzunehmen (einschließlich all der
>str*-Funktionen). Für diesen Zweck ist es auch völlig belanglos, ob das
>“char” nun
>vorzeichenbehaftet ist oder nicht.

Stimmt, das verstehe sogar ich.

>Wer eine kleine Ganzzahl mit mindestens 8 Bits benötigt, hat die
>Wahl zwischen “[u]int_fast8_t” oder “[u]int_least8_t”, je nachdem, ob
>ihm die Geschwindigkeit oder das Platzsparen wichtiger ist.  Damit kann
>man relativ portabel ausdrücken, dass zwar 8 Bits genügen für den
>Zweck, aber (uint_fast8_t) eben auf einem ARM der Datentyp auch ruhig
>größer sein darf (weil es schneller geht so), oder aber (uint_least8_t)
>eine Umgebung wie die genannten DSPs, die keinen 8-Bit-Typ besitzt,
>eben dann einen größeren wählen darf.

Da kann ich auch mitgehen.

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> Gibt solche Leute im realen Leben? ;-)

Max gewöhnt sich mit der Zeit dran, es richtig zu machen ...

>>Seit C99 gibt's ja nun auch keinerlei Grund mehr, für solche Fälle
>>den Typ “char” zu benutzen:

... wenn man das mal verinnerlicht hat. Oder vorher schon seine eigenen 
ähnlichen Typedefs dafür verwendete.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Dieser ganze Problemkreis ist IMHO in der Praxis gar nicht so sehr das 
Problem. Viel schwieriger ist es mit den Datentypen in Expressions klar 
zu kommen
1
uint16_t value1 = 20000;
2
uint16_t value2 = 20000;
3
4
uinat32_t result = value1 * value2;

das ist jetzt natürlich ein triviales Beispiel, welches nur einen Punkt 
illustrieren soll:
Auf einem System mit 16 Bit int geht die Berechnung schief. Auf einem 
System mit 32 Bit int ist das Ergebnis korrekt.

Klar, kann man das mit Casts alles richtig stellen, aber praktisch 
gesehen würde das bedeuten, dass man viele Programmen mit Casts 
regelrecht spicken müsste. Was natürlich nicht passiert. D.h. auch mit 
dieser MISRA Regelung bleibt es nicht erspart, dass man die 'basic 
types' und ihr Verhalten bzw. die davon abhängigen C-Regeln kennen muss 
um auf der sicheren Seite zu sein.
1
The basic type of char, int, short, long, float and double should not be used, but specific-
2
length equivalents should be typedef'd for the specific compiler, and these type names
3
used in the code.
greift zu kurz, weil es nicht vollständig auf die Datentypen von 
Zwischenergebnissen wirkt.

>
>
1
> The library functions atof, atoi and atol from library <stdlib.h> shall not be used.
2
>
Selbes Problem. Da stecken implizite Annahmen über die basic datatypes 
drinnen.

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Klar, kann man das mit Casts alles richtig stellen, aber praktisch
> gesehen würde das bedeuten, dass man viele Programmen mit Casts
> regelrecht spicken müsste.

Wobei das nur bei Typen ab (u)int32_t relevant ist.

In C kann man statt Casts auch das geringfügig elegantere 
INT32_C(literal) verwenden. Nur ist man dann in C++ geleimt, denn da 
fand es offenbar jemand angesichts von int32_t(literal) unnötig.

von Kindergärtner (Gast)


Lesenswert?

A. K. schrieb:
> Nur ist man dann in C++ geleimt,
In C++ haben Integer-Literale automatisch den "richtigen" Datentyp, und 
zwar den kleinsten ausreichenden, aber mindestens "int". In C++ möchte 
man halt nicht für jeden Datentyp noch ein Makro haben um dahin zu 
casten, sondern verwendet entweder explizite casts: 
static_cast<uint_least32_t>(eine16bitzahl) oder Konstruktion: 
uint_least32_t { eine16bitzahl }.

von (prx) A. K. (prx)


Lesenswert?

Kindergärtner schrieb:
> In C++ haben Integer-Literale automatisch den "richtigen" Datentyp, und
> zwar den kleinsten ausreichenden, aber mindestens "int".

Das ist in C auch so. Zum Problem wird es bei Ausdrücken der Art
   50000 * 2
die man schon gerne in 32 Bits rechnen will, aber nicht unbedingt in 64 
Bits. Und das ist ohne irgendwelchen Zirkus drumrum nicht universell 
möglich.

Der Vorteil der Makros wie INT32_C(n) gegenüber (int32_t)(n) oder 
int32_t(n) liegt in der grösseren Sicherheit, wenn hinter dem INT32_C 
nicht wiederum ein Cast steckt, sondern beispielsweise etwas wie
   #define INT32_C(n)  n ## L
Denn dann kriegt man bei fehlerhafter Verwendung zwar lustige 
Fehlermeldungen, riskiert aber nicht, hier versehentlich einen Pointer 
oder schlimmeres in int32_t zu casten.

Ich mag Casts nicht so, diese Dinger sind mir etwas zu brachial. Ein 
Cast frisst alles was auch nur im entferntesten konvertierbar ist.

von Karl H. (kbuchegg)


Lesenswert?

A. K. schrieb:

> Ich mag Casts nicht so, diese Dinger sind mir etwas zu brachial. Ein
> Cast frisst alles was auch nur im entferntesten konvertierbar ist.

Oder wie ich es gerne ausdrücke:
Ein Cast ist die C Schreibweise für "Halt die Klappe und mach es 
einfach"

von Sven P. (Gast)


Lesenswert?

Diese 'usual arithmetic conversions' ziehen aber noch viel schönere 
Kreise:
1
int x = -1;
2
unsigned int y = 0;
3
4
if (x < y)
5
        puts("x < y");
6
else if (x > y)
7
        puts("x > y");

Ist alles nicht so einfach :-}

von Werner (Gast)


Lesenswert?

c2000 schrieb:
> Mit nichten! Ein char kann auch z.B. 16 bit lang sein. Z.B. beim C2000
> ist ein char immer 16 bit!

Char kann bei einigen DSP auch 24bit sein.

von Werner (Gast)


Lesenswert?

A. K. schrieb:
> Ich könnte mir freilich vorstellen, dass man bei einer Architektur,
> deren chars 16 Bits haben, mit (u)int8_t nicht glücklich wird.

Das ist nicht weiter problematisch, das eigentlich Problem ist der 
doppelte Speicherverbrauch, auch bei simplen Strings.

von Kindergärtner (Gast)


Lesenswert?

A. K. schrieb:
> die man schon gerne in 32 Bits rechnen will, aber nicht unbedingt in 64
> Bits. Und das ist ohne irgendwelchen Zirkus drumrum nicht universell
> möglich.
Tjo, man muss sich halt vorher den Wertebereich überlegen und 
casten/konstrukten. Wird ggf etwas unübersichtlich... Gilt auch hier:

Karl Heinz Buchegger schrieb:
> Auf einem System mit 16 Bit int geht die Berechnung schief. Auf einem
> System mit 32 Bit int ist das Ergebnis korrekt.
Letzteres kann sein, muss aber nicht; hängt davon ab ob es eine 
16bit-Multiplikations-Instruktion gibt und wie sich die CPU beim 
Überlauf verhält; ist undefiniertes Verhalten und 
plattform/Compiler-abhängig.

A. K. schrieb:
> riskiert aber nicht, hier versehentlich einen Pointer
> oder schlimmeres in int32_t zu casten.
In C, ja. In C++ kann man wie oben angemerkt static_cast<uint32_t>() 
oder uint32_t{} verwenden, was ebenfalls das Casten von Pointern o.ä. 
verweigert und außerdem keine lustigen Syntaxerrors produziert.

A. K. schrieb:
> Ein
> Cast frisst alles was auch nur im entferntesten konvertierbar ist.
Deswegen hat C++ hat die benannten Casts, wo man explizit angibt was 
dieser Cast machen soll, und wenn das so nicht geht gibts einen 
Compilerfehler.

von (prx) A. K. (prx)


Lesenswert?

Werner schrieb:
> Das ist nicht weiter problematisch,

Wenn man diesen Typ in übernommenem Quellcode an tausend Stellen stehen 
hat schon. Erst recht, wenn dann auch noch ein Protokoll existiert, dass 
8-Bit Bytes voraussetzt.

> das eigentlich Problem ist der
> doppelte Speicherverbrauch, auch bei simplen Strings.

Wenn man sowieso exotisch programmieren muss, weshalb dann nicht 
konsequent? Also mit 3 oder 4 Zeichen in einem 24 Bit Wort. ;-)

Es hat auch schon Systeme gegeben, in denen platzsparenderweise 3 
Zeichen in 16 Bits codiert wurden (Radix 50).

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


Lesenswert?

A. K. schrieb:
> Es hat auch schon Systeme gegeben, in denen platzsparenderweise 3
> Zeichen in 16 Bits codiert wurden (Radix 50).

Ja, kenn ich auch noch.  PDP-11-Zeiten lassen grüßen.

Neulich habe ich eine Beschreibung gelesen, bei der jemand sowas in der
Jetztzeit wiedererfunden hat.  Natürlich nicht etwas dasselbe, was DEC
seinerzeit als Radix-50 benutzt hat, das wäre wohl zu einfach gewesen. 
:/

Allerdings muss man sagen, dass auf diesen Systemen R50 nicht den Typ
"char" hatte.

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:
> Natürlich nicht etwas dasselbe, was DEC seinerzeit als Radix-50

Ausserdem hätte heute niemand mehr verstanden, wieso das Radix-50 
heisst, wo es doch 40 Zeichen codiert. ;-)

von Stefan R. (srand)


Lesenswert?

Werner schrieb:
> Char kann bei einigen DSP auch 24bit sein.

Nein.

Wolltest du nicht künftig einen Thread erst lesen, bevor du 
kommentierst?

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


Lesenswert?

Stefan Rand schrieb:
>> Char kann bei einigen DSP auch 24bit sein.
>
> Nein.

Mir ist zwar kein Beispiel bekannt, aber so ein definitives "Nein"
würde ich da nicht hinschreiben.  Selbstverständlich kann es das
sein, vom C-Standard her wäre das völlig in Ordnung.

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

Jörg Wunsch schrieb:
> Mir ist zwar kein Beispiel bekannt,

Der 56k von Motorola wäre so ein Beispiel.

Im Anhang ein Ausschnitt dem "Motorola DSP56000 Family Optimizing C 
Compiler User's Manual".

von Stefan R. (srand)


Lesenswert?

Jörg Wunsch schrieb:
> Mir ist zwar kein Beispiel bekannt, aber so ein definitives "Nein"
> würde ich da nicht hinschreiben.  Selbstverständlich kann es das
> sein, vom C-Standard her wäre das völlig in Ordnung.

Stimmt, ich habe nicht richtig gelesen.

von Werner (Gast)


Lesenswert?

Stefan Rand schrieb:
> Werner schrieb:
>> Char kann bei einigen DSP auch 24bit sein.
>
> Nein.
>
> Wolltest du nicht künftig einen Thread erst lesen, bevor du
> kommentierst?

Nein, aber du bist jetzt etwas schlauer ...

Beitrag "Re: Fragen zu MISRA"

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
1
> The basic type of char, int, short, long, float and double should not be 
2
> used, but specific-
3
> length equivalents should be typedef'd for the specific compiler, and 
4
> these type names
5
> used in the code.
> greift zu kurz, weil es nicht vollständig auf die Datentypen von
> Zwischenergebnissen wirkt.

ACK, sicher greift das zu kurz.  Aber MISRA kann ja nicht die 
Integer-Promotion-Regeln neu definieren.  Oder es müsste fordern, daß 
Programme so zu schreiben sind, dass sie

- So geschrieben sind, als sei int nur 16 Bits groß

- In einer Cast-Orgie ausarten

In der Praxis beobachte ich die 2te alternative.  Der Code ist gespickt 
mit Makros, die zu den eigentlichen Operationen expandieren und 
fleissigst Casts einfügen.

Das führt dann zu Code mit Zeilen, die mehrere hundert Zeichen lang sind 
und zu 90% aus Casts bestehen.

Hört sich übel an, ist aber so — zumindest für den Code von Kunden, den 
ich hin und wieder mal zu Gesicht bekomme.

Falk Brunner schrieb:
> @ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
>
>>> Welcher (C)-Programmierer geht denn NICHT davon aus, dass char 8 Bit
>>> hat?
>
>>Jemand, der den Standard ernst nimmt und sich bei dieser Annahme der
>>nicht strikten Konformität seiner Applikation bewusst ist.
>
> Gibt solche Leute im realen Leben? ;-)

Zumindest unter den zig (offiziellen) Architekturen, die GCC 
unterstützt, gibt's m.W. keine einzige, die für BITS_PER_UNIT einen 
anderen Wert als 8 verwendet, also Bytes mit 8 Bits.

Hin und wieder gibt's Fragen in den Mailing-Listen bezüglich 
BITS_PER_UNIT > 8 für irgendwelche Sonderlocken gedrechselten, 
hausbackenen Architekturen.  Unterstützung dafür gibt's aber nicht...

: Bearbeitet durch User
von Steffen Rose (Gast)


Lesenswert?

> ACK, sicher greift das zu kurz.  Aber MISRA kann ja nicht die
> Integer-Promotion-Regeln neu definieren.  Oder es müsste fordern, daß
> Programme so zu schreiben sind, dass sie
>
> - So geschrieben sind, als sei int nur 16 Bits groß
>
> - In einer Cast-Orgie ausarten
>
> In der Praxis beobachte ich die 2te alternative.  Der Code ist gespickt
> mit Makros, die zu den eigentlichen Operationen expandieren und
> fleissigst Casts einfügen.
>
> Das führt dann zu Code mit Zeilen, die mehrere hundert Zeichen lang sind
> und zu 90% aus Casts bestehen.

Misra fordert u.a., dass der Programmierer zeigt, was vor sich geht.
Das bedeutet, dass implizite Typwandlungen (z.B. durch die Integer 
Promotion Regeln verursacht) verpönt sind. Hier kann nicht geprüft 
werden, ob der Programmierer dieses Verhalten bedacht hat. Daher muss 
jede Typwandlung mit einem cast angezeigt werden.


> Zumindest unter den zig (offiziellen) Architekturen, die GCC
> unterstützt, gibt's m.W. keine einzige, die für BITS_PER_UNIT einen
> anderen Wert als 8 verwendet, also Bytes mit 8 Bits.

Die Diskussion macht nur dann Sinn, wenn Du Code schreiben willst, 
welcher auf verschiedenen Umgebungen läuft. Sei es, weil dein Code über 
Jahre genutzt wird und sich die Welt weiterdreht. Oder sei es, weil du 
verschiedene Projekte für verschiedene Kunden mit unterschiedlichen 
Umgebungen bearbeitest.

von Rolf Magnus (Gast)


Lesenswert?

A. K. schrieb:
> Zum Problem wird es bei Ausdrücken der Art
>    50000 * 2
> die man schon gerne in 32 Bits rechnen will, aber nicht unbedingt in 64
> Bits.

Streng genommen möchte man sie nicht zwingend in 32 Bit, aber in einem 
Datentyp rechnen, der groß genug ist, um 100000 aufzunehmen. Man 
bräuchte also eigentich die Möglichkeit, einen gewünschten 
Minimal-Wertebereich anzugeben. In C++ könnte man sich mit Templates 
dafür sogar was stricken.

Jörg Wunsch schrieb:
> A. K. schrieb:
>> Es hat auch schon Systeme gegeben, in denen platzsparenderweise 3
>> Zeichen in 16 Bits codiert wurden (Radix 50).
>
> Ja, kenn ich auch noch.  PDP-11-Zeiten lassen grüßen.

Wenn man bei modernen Systemen nach ulkigend Datentypen sucht, wird man 
bei den Grafikkarten fündig. Da gibt's sogar einen Datentyp, der in 32 
Bit drei Gleitkommazahlen mit gemeinsamem Exponent speichert.

von Sven P. (Gast)


Lesenswert?

Steffen Rose schrieb:
> Misra fordert u.a., dass der Programmierer zeigt, was vor sich geht.
> Das bedeutet, dass implizite Typwandlungen (z.B. durch die Integer
> Promotion Regeln verursacht) verpönt sind. Hier kann nicht geprüft
> werden, ob der Programmierer dieses Verhalten bedacht hat. Daher muss
> jede Typwandlung mit einem cast angezeigt werden.
Was natürlich voraussetzt, dass der Programmierer damit umgehen kann. 
Mit einem Cast hat man auch gerne schnell einen Überlauf plattgemacht 
o.ä.

von Steffen R. (steffen_rose)


Lesenswert?

Sven P. schrieb:
> Was natürlich voraussetzt, dass der Programmierer damit umgehen kann.
> Mit einem Cast hat man auch gerne schnell einen Überlauf plattgemacht
> o.ä.

Fehler können in beiden Fällen gemacht werden. Klar.

Wobei der Misra Checker schon davor warnt, wenn man "runter-casted". Der 
Vorteil von expliziten cast's gegenüber impliziten cast's ist 
hauptsächlich, dass ein zweiter Mensch formaler prüfen kann. Er muss 
nicht ständig über die Datentypen grübeln.

Ich denke, viele hier werden Schwierigkeiten haben, die Integer 
Promotion (heißt es nicht Integral Promotion?) Regeln zu erläutern. Bei 
expliziten cast's ist das einfacher, solange man natürlich auf gleiche 
Typen cast'ed.

Steffen

von Coder (Gast)


Lesenswert?

Also üblicherweise benutzt man ein statische Analyse Tool, dass MISRA C 
kann. Der wird einen warnen, wenn das Risiko eines Überlaufs besteht.

von Steffen R. (steffen_rose)


Lesenswert?

Üblicherweise kombiniert man mehrere Methoden. Und dabei sollte eine 
Codedurchsicht nicht fehlen.

von Robert K. (Firma: Medizintechnik) (robident)


Lesenswert?

Für die Prüfung von C-code gibt es einige Stellen, die das übernehmen 
und dokumentieren. Die arbeiten zeilenweise.

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.