Forum: Mikrocontroller und Digitale Elektronik Byte Array/Word-Array


von Walter T. (nicolas)


Lesenswert?

Guten Abend,

ich versuche mich gerade an einer Art "Code Review" meines eigenen 
Quelltextes. Dass das nur mittelmäßig gut funktioniert, ist klar. Aber 
ich habe halt nichts Besseres.

Ich habe im Speicher ein relativ großes Byte Array, das als 
Allzweckpuffer dient:
1
/* Allzweckpuffer. 
2
   Regel: Nur die Funktion, die hineingeschrieben hat, darf auch wieder daraus lesen. */
3
#define AUXBUFFERSIZE_BYTES 8192
4
uint8_t glAuxbuffer[AUXBUFFERSIZE_BYTES];

Bislang habe ich, wenn ich den Puffer gefüllt oder ausgelesen habe, 
immer brav jedes Byte einzeln behandelt. Der Compiler ist natürlich so 
schlau, daraus wieder Ganz- oder Halbwortzugriffe zu machen, wenn es 
möglich ist. Aber der Quelltext ist natürlich immer noch unübersichtlich 
und damit fehlerträchtig, wenn man jedes Wort beim Schreiben zerlegt und 
beim Wiederlesen zusammensetzt.

Ist es erlaubt®, ein Byte Array mit einem z.B. 16-Bit-Zeiger als Alias 
zu nutzen?
1
uint16_t *mybuffer = (uint16_t *) glAuxbuffer;
2
uint_fast16_t bufferSize = AUXBUFFERSIZE_BYTES/2;
3
for( int i = 0; i<bufferSize; i++)
4
{
5
    *(myBuffer++) = giveMeASixteenBitValue(i);
6
}
Eine Warnung bekomme ich nicht. Klar, die ist ja auch totgecastet. Das 
Assembler-Listing sieht auch passend aus. Aber ich kenne keine C-Regel, 
die das erlaubt.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Lass das besser bleiben. Auf ein Array von Bytes greift man Byte-weise 
zu. Alles andere stiftet nur Verwirrung und provoziert Probleme.

Du geht ja auch nicht im Straßenverkehr hin und setzt den Blinks links 
wenn du nach rechts fahren willst.

von c-hater (Gast)


Lesenswert?

Walter T. schrieb:

> Ist es erlaubt®, ein Byte Array mit einem z.B. 16-Bit-Zeiger als Alias
> zu nutzen?

Natürlich ist es "erlaubt". Bloß nicht portabel. Das funktioniert so nur 
bei little endian Maschinen. Und dann auch nicht unbedingt immer.

endianess und alignment könnten das Gebäude zum Einsturz bringen.

von Norbert (Gast)


Lesenswert?

Wenn man mal von möglichen alignment Problemen absieht, sehe ich nicht 
das geringste Problem darin.

von Walter T. (nicolas)


Lesenswert?

c-hater schrieb:
> Das funktioniert so nur
> bei little endian Maschinen

Warum? Der Adresszeiger liegt immer vorn.

Norbert schrieb:
> Wenn man mal von möglichen alignment Problemen absieht

Du meinst das Byte wäre Word-Aligned und ich verschenke Speicherplatz?

Okay...es geht bei beiden Beiträgen Richtung "ungutes Gefühl". Dann ist 
wohl ein union das Mittel der Wahl.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Norbert schrieb:

> Wenn man mal von möglichen alignment Problemen absieht, sehe ich nicht
> das geringste Problem darin.

Dann musst du noch viel lernen.

von Norbert (Gast)


Lesenswert?

c-hater schrieb:
> Norbert schrieb:
>
>> Wenn man mal von möglichen alignment Problemen absieht, sehe ich nicht
>> das geringste Problem darin.
>
> Dann musst du noch viel lernen.

Gerne, erklär mal bitte.

von mitlesa (Gast)


Lesenswert?

Walter T. schrieb:
> Warum? Der Adresszeiger liegt immer vorn.

Würde sagen dass der Zeiger bei einer von beiden Endianess-
Versionen falsch steht.

von mitlesa (Gast)


Lesenswert?

mitlesa schrieb:
> Würde sagen dass der Zeiger bei einer von beiden Endianess-
> Versionen falsch steht.

Es sei denn du hast die Byte-Order and die Endianess angepasst.

von c-hater (Gast)


Lesenswert?

Walter T. schrieb:

> Warum? Der Adresszeiger liegt immer vorn.

Ja. Genau das ist ja das Problem. "Vorn" ist halt bei big endian was 
anderes als bei little endian.

> Dann ist
> wohl ein union das Mittel der Wahl.

Sicher nicht. Da stellt sich exakt das gleiche Problem. Nicht portabel.

von Stefan F. (Gast)


Lesenswert?

Ein byte Array darf an beliebigen Positionen im RAM liegen, weil man 
Byte-weise darauf zugreift.

Bei vielen Mikrocontrollern müssen 16 bit Werte aber an geraden 
Adressen liegen, sonst können sie nicht darauf zugreifen.

Bei anderen wiederum sollte es so sein, weil sie sonst deutlich 
langsamer werden. Was blöd ist, weil dieser Code ja aus der Idee heraus 
kam, ihn zu beschleunigen.

Wenn das Array z.B. an Adresse 101 beginnt, und ich das erste Word (16 
Bit) davon lesen will, habe ich schon verloren. Es sei denn, ich weiß 
mit Sicherheit, dass beim vorliegenden Mikrocontroller das aligning 
keine Rolle spielt. Das wäre aber eher eine Ausnahme als der Regelfall.

Viel wichtiger ist mir aber die Lesbarkeit des Codes. Wenn ich Birnen 
verarbeiten will, dann benutze ich nicht Befehle für Äpfel. Wenn ich 
beim Bäcker vier halbe Roggenbrote bestelle, dann will ich nicht zwei 
ganze Brote bekommen. Wir sind hier nicht beim Fußball, wo das 
Antäuschen (nur gegenüber dem Gegner) eine sinnvolle Taktik ist.

von Dirk B. (dirkb2)


Lesenswert?

Walter T. schrieb:
> uint16_t *mybuffer = (uint16_t *) glAuxbuffer;
> uint_fast16_t bufferSize = AUXBUFFERSIZE_BYTES/2;
> for( int i = 0; i<bufferSize; i++)
> {
>     *(myBuffer++) = giveMeASixteenBitValue(i);
> }

Du kannst so nicht wissen, dass sizeof(uint_fast16_t) = 2 ist.
Es ist die schnellste Version für 16 Bit. Das können auch 32 Bit sein. 
Oder 24, ....
Aber schreib jetzt nicht statt der 2 sizeof(uint_fast16_t) sondern 
sizeof(bufferSize)

Warum machst du keine union, da wird dann schon passend auf das 
Alignement geachtet - oder du nimmst Compiler-Erweiterungen.

von mh (Gast)


Lesenswert?

c-hater schrieb:
> Walter T. schrieb:
>
>> Ist es erlaubt®, ein Byte Array mit einem z.B. 16-Bit-Zeiger als Alias
>> zu nutzen?
>
> Natürlich ist es "erlaubt". Bloß nicht portabel. Das funktioniert so nur
> bei little endian Maschinen. Und dann auch nicht unbedingt immer.

Es ist verboten.
1
6.5 Expressions
2
7) An object shall have its stored value accessed only by an lvalue expression that has one of the following types:89)
3
— a type compatible with the effective type of the object,
4
— a qualified version of a type compatible with the effective type of the object,
5
— a type that is the signed or unsigned type corresponding to the effective type of the object,
6
— a type that is the signed or unsigned type corresponding to a qualified version of the effective
7
type of the object,
8
— an aggregate or union type that includes one of the aforementioned types among its members
9
(including, recursively, a member of a subaggregate or contained union), or
10
— a character type.

von Walter T. (nicolas)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ein byte Array darf an beliebigen Positionen im RAM liegen, weil man
> Byte-weise darauf zugreift.

Liegt es aber nicht. Ich habe in meinem ganzen Assembler-Listing kein 
einziges nicht Wort-ausgerichtetes Byte-Array gesehen.

Ich wüßte auch nicht, warum es das geben solle. Es liegt schließlich 
hinter einem Zeiger in Wortbreite.

c-hater schrieb:
> Sicher nicht. Da stellt sich exakt das gleiche Problem. Nicht portabel.

Hier definitiv: Doch. Ich darf beim union immer das auslesen, was ich 
auch geschrieben habe. Genau dafür ist es da.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Walter T. schrieb:

> Hier definitiv: Doch. Ich darf beim union immer das auslesen, was ich
> auch geschrieben habe. Genau dafür ist es da.

Klar. Und es knallt genau dann, wenn du den Inhalt der Union zwischen 
Schreiben und Lesen von einer Maschine auf eine andere überträgst und 
diese Maschinen unterschiedliche endianess haben.

Das kann doch nicht so schwer zu begreifen sein?

Aber das Beispiel mit dem Übertragen auf eine andere Maschine ist nur 
der Extremfall, wo es sofort klar wird. Viel gefährlicher ist, dass 
solche Konstrukte gern dazu eingesetzt werden, aus Bytes größere Werte 
größerer Datentypen "zusammenzubauen" (oder auch für die umgekehrte 
Operation).

Der Code, der das tut, ist halt nicht portabel. Er funktioniert nur bei 
einer endianess, derselbe Code auf einer Maschine mit anderer 
endianess macht Bullshit.

Genau das ist mit portabel gemeint: der Code sollte unabhängig von der 
endianess funktionieren.

von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
> Liegt es aber nicht. Ich habe in meinem ganzen Assembler-Listing kein
> einziges nicht Wort-ausgerichtetes Byte-Array gesehen.

Das ist ja schön für dich, aber darauf ist kein Verlass.

> Es liegt schließlich hinter einem Zeiger in Wortbreite.

Auch darauf ist kein Verlass. Wo die Daten im Speicher abgelegt werden 
und in welcher Reihenfolge, das ist nicht festgelegt.

Die Programmiersprache C sichert viele Eigenschaften zu und lässt einige 
offen, damit sie auf jeder Plattform einigermaßen performant umgesetzt 
werden kann. Du verlässt dich hier auf eine Eigenschaft, die nicht 
zugesichert wurde.

"Na los, du bist nicht zu schwer! Seile halten immer doppelt so viel als 
auf der Verpackung steht."

von Walter T. (nicolas)


Lesenswert?

c-hater schrieb:
> Klar. Und es knallt genau dann, wenn du den Inhalt der Union zwischen
> Schreiben und Lesen von einer Maschine auf eine andere überträgst und
> diese Maschinen unterschiedliche endianess haben.

Wie soll das gehen? Wenn ich Daten zwischen Maschinen austausche, 
brauche ich ein Protokoll, und da muss ich natürlich auf Network Byte 
Order achten.

Und wenn ich das Programm von einem auf den anderen Rechner übertrage, 
wird das union von jedem im Programmverlauf frisch befüllt und wieder in 
der Reihenfolge ausgelesen, wie es geschrieben wurde.

Ich habe zwar schon vom Begriff "Bit rot" gehört, aber das ist 
lächerlich. Bei jedem union kann ich auf jeder Maschine jedes Datum so 
auslesen, wie ich es gespeichert habe - solange der Speicher in Ordnung 
ist.

von Nop (Gast)


Lesenswert?

Walter T. schrieb:

> Ich wüßte auch nicht, warum es das geben solle. Es liegt schließlich
> hinter einem Zeiger in Wortbreite.

Nein. tut es nicht. Ein Array ist kein struct aus einem Zeiger und einem 
Datenteil, sondern ein Array ist eine feste Adresse, hinter der X Bytes 
Speicher reserviert sind. Es ist an Speicher also nur der Array-Inhalt 
belegt.

Ich habe mit sowas schon bei einem Compilerupdate schon Probleme gehabt, 
als ein Array aus uint8_t über uint32_t angesprochen wurde. Wenn Du 
sowas machen willst, benutz das Alignment-Attribut für das Array.

von c-hater (Gast)


Lesenswert?

Walter T. schrieb:

> Wie soll das gehen?

Spiele es doch einfach mal real durch. Dann verstehst vielleicht sogar 
du das Problem.

Naja, an little endian Maschinen herrscht kein Mangel, bei big endian 
wird's mittlerweile etwas eng...

von Walter T. (nicolas)


Lesenswert?

c-hater schrieb:
> Spiele es doch einfach mal real durch.

Kann es sein, dass Du die zweite Zeile im Listing nicht gelesen hast?

Walter T. schrieb:
> /* Allzweckpuffer.
>    Regel: Nur die Funktion, die hineingeschrieben hat, darf auch wieder
> daraus lesen. */

Es geht nicht um type punning. Es geht darum, jeweils innerhalb von 
einer Funktion (evtl. mit Unterfunktionen) Daten aufzubewahren. 
(Hauptsächlich entpackte oder generierte Daten kurz puffern.)

Nop schrieb:
> [...] sondern ein Array ist eine feste Adresse, hinter der X Bytes
> Speicher reserviert sind. Es ist an Speicher also nur der Array-Inhalt
> belegt.
>
> Ich habe mit sowas schon bei einem Compilerupdate schon Probleme gehabt,
> als ein Array aus uint8_t über uint32_t angesprochen wurde. Wenn Du
> sowas machen willst, benutz das Alignment-Attribut für das Array.

Das klingt sinnvoll und plausibel. Danke!

: Bearbeitet durch User
von Norbert (Gast)


Lesenswert?

Mittlerweile wird hier ja nun wirklich verzweifelt nach Gründen gesucht, 
warum man dies und das nicht... jetzt sind wir schon bei Rechner zu 
Rechner Transfer.

Fakt ist: Wir haben einen Speicherbereich auf den man mit Hilfe von 
Pointern zugreifen möchte. Alignment vorausgesetzt, kann man auf den 
Beginn des Speicherbereiches mit (u)int8_t *,(u)int16_t *,(u)int32_t 
*,... zugreifen. Das ist ein Mechanismus mit dem schon im letzten 
Jahrtausend gearbeitet wurde, vermutlich auch noch im Nächsten.
Man sollte/darf nicht mit einem Pointer schreiben und mit einem anderen 
lesen, das wäre in der Tat ein Problem. Endianess wurde schon erwähnt.
Doch wenn man mit uintxx_t * schreibt und liest, passiert präzise gar 
nichts Schlimmes. <--Punkt

von A. S. (Gast)


Lesenswert?

Ich verwende für general purpose Speicher eine typedef BYTE, das i.d.R. 
auf char lautet. Damit ist ein cast erlaubt und OK (typedef, damit 
erkennbar ist, dass es kein uint8_t oder so ist, sondern g.p.Speicher).

Du kannst auch ohne union beliebige Typen auf den Speicher abbilden, 
solange Du das zurückliest, was Du reingeschrieben hast, WENN Dein Array 
für alle Typen korrekt aligned ist.

Endianess spielt keine Rolle, es sei denn, Du willst da selber Zahlen 
zusammenbasteln.

Speichergröße für Deine Typen spielt auch keine Rolle, solange Du halt 
die Arraygrenzen nicht verlässt.

Also ja, mach dass, wenn Du das Allignment nötigenfalls sicherstellen 
kannst.

Es ist portabel, erlaubt, gut und üblich.

von mh (Gast)


Lesenswert?

A. S. schrieb:
> Es ist portabel, erlaubt, gut und üblich.

Wo genau steht, dass es erlaubt ist?

von Norbert (Gast)


Lesenswert?

Ein malloc liefert einen void Pointer auf einen Speicherbereich,
den void Pointer castet man sich selbst passend.
Was zum Henker spricht dagegen mal mit einen uint8_t* zu lesen und zu 
schreiben, mal mit einem uint16_t* zu lesen und zu schreiben?

von mh (Gast)


Lesenswert?

Norbert schrieb:
> Ein malloc liefert einen void Pointer auf einen Speicherbereich,
> den void Pointer castet man sich selbst passend.
> Was zum Henker spricht dagegen mal mit einen uint8_t* zu lesen und zu
> schreiben, mal mit einem uint16_t* zu lesen und zu schreiben?

Der Standard, wie oben zitiert.

von Stefan F. (Gast)


Lesenswert?

Norbert schrieb:
> Was zum Henker spricht dagegen

Nichts, weil malloc immer das Aligment für den größten möglichen 
Datentyp anwendet. Auf einem PC ist die Adresse immer durch 8 teilbar.

von Norbert (Gast)


Lesenswert?

Du meine Güte!
uint16_t *ptr16 = malloc(1024);
uint8_t *ptr8 = (uint8_t *)ptr16;  (**)
Beide zeigen präzise auf die gleiche Stelle, incrementieren aber anders.

(**)Von mir aus auch mit reinterpret_cast<uint8_t *>

von Norbert (Gast)


Lesenswert?

War nicht an dich gerichtet, Stefan.

von c-hater (Gast)


Lesenswert?

Norbert schrieb:

> Doch wenn man mit uintxx_t * schreibt und liest, passiert präzise gar
> nichts Schlimmes. <--Punkt

So ist es. Solange man zwischen Schreiben und Lesen den Datentyp nicht 
wechselt, gibt es auch kein Problem.

von mh (Gast)


Lesenswert?

Norbert schrieb:
> Du meine Güte!
> uint16_t *ptr16 = malloc(1024);
> uint8_t *ptr8 = (uint8_t *)ptr16;  (**)
> Beide zeigen präzise auf die gleiche Stelle, incrementieren aber anders.
>
> (**)Von mir aus auch mit reinterpret_cast<uint8_t *>

So rum ist erlaubt, wie du oben oder im Standard nachlesen kannst

von Norbert (Gast)


Lesenswert?

mh schrieb:

> So rum ist erlaubt, wie du oben oder im Standard nachlesen kannst

Nun, erlaubt ist beides, jedoch garantiert problemlos ist nur von 
stärker nach schwächer. (Alignment)
1
A pointer to one type may be converted to a pointer to another type. The resulting pointer may cause addressing exceptions if the subject pointer does not refer to an object suitably aligned in storage. It is guaranteed that a pointer to an object may be converted to a pointer to an object whose type requires less or equally strict storage alignment and back again without change.

von mh (Gast)


Lesenswert?

Norbert schrieb:
> mh schrieb:
>
>> So rum ist erlaubt, wie du oben oder im Standard nachlesen kannst
>
> Nun, erlaubt ist beides, jedoch garantiert problemlos ist nur von
> stärker nach schwächer. (Alignment)
> A pointer to one type may be converted to a pointer to another type. The
> resulting pointer may cause addressing exceptions if the subject pointer
> does not refer to an object suitably aligned in storage. It is
> guaranteed that a pointer to an object may be converted to a pointer to
> an object whose type requires less or equally strict storage alignment
> and back again without change.

Das erlaubt dir den Pointer zu konvertieren, aber sagt dir nicht, was du 
mit dem Pointer machen darfst. Wie gesagt, ich habe oben den relevanten 
Teil zitiert.

von Norbert (Gast)


Lesenswert?

mh schrieb:
> Norbert schrieb:
>> mh schrieb:
> Das erlaubt dir den Pointer zu konvertieren, aber sagt dir nicht, was du
> mit dem Pointer machen darfst. Wie gesagt, ich habe oben den relevanten
> Teil zitiert.

Wenn ich einen /oder mehrere) Pointer konvertiere und diese dann nicht 
benutze, würde ich mir schon ernsthafte Sorgen machen;-)

Es wird aber explizit erwähnt das es zu Exceptions kommen könnte, das 
würde aber nur passieren wenn solche Pointer auch verwendet würden.
Somit wird impliziert das diese Pointer auch verwendet werden können.
Ansonsten wäre die ganze Passage obsolet.

von mh (Gast)


Lesenswert?

Norbert schrieb:
> ...
Du kannst glauben was du willst. Solange du aber nicht erklären kannst, 
warum das explizite Verbot, das im Standard steht und oben zitiert 
wurde, nicht gilt, bleibt es verboten.

von Al Fine (Gast)


Lesenswert?

mh schrieb:
> Es ist verboten.6.5 Expressions
> 7) An object shall have its stored value accessed only by an lvalue
> expression that has one of the following types:89)
> ...

Fehler in der Argumentation: Es wird hier nicht auf den gespeicherten 
Wert der uint8_t zugegriffen.

von mh (Gast)


Lesenswert?

Al Fine schrieb:
> mh schrieb:
>> Es ist verboten.6.5 Expressions
>> 7) An object shall have its stored value accessed only by an lvalue
>> expression that has one of the following types:89)
>> ...
>
> Fehler in der Argumentation: Es wird hier nicht auf den gespeicherten
> Wert der uint8_t zugegriffen.

Was meinst du mit "hier"? In dem Beispiel des TO wird es das sehr wohl. 
Die Lebenszeit eines Objekt beginnt, wenn der Speicher garantiert zur 
Verfügung steht. Ein Objekt hat während seiner Lebenszeit einen Wert. 
Dieser Wert mag "indeterminate" sein, dann ist der lesende Zugriff UB.

von Jemand (Gast)


Lesenswert?

Norbert schrieb:
> Es wird aber explizit erwähnt das es zu Exceptions kommen könnte, das
> würde aber nur passieren wenn solche Pointer auch verwendet würden.
> Somit wird impliziert das diese Pointer auch verwendet werden können.

Die neuere Fassung hat da eine andere Meinung
1
A pointer to an object type may be converted to a pointer to a different object type. If the resulting
2
pointer is not correctly aligned for the referenced type, the behavior is undefined. Otherwise,
3
when converted back again, the result shall compare equal to the original pointer. When a pointer to
4
an object is converted to a pointer to a character type, the result points to the lowest addressed byte
5
of the object. Successive increments of the result, up to the size of the object, yield pointers to the
6
remaining bytes of the object.

von aliasing (Gast)


Lesenswert?

https://gustedt.wordpress.com/2016/08/17/effective-types-and-aliasing/

- auf ein char array darf man nur per char* zugreifen.
- auf ein int16 array darf man per int16* und per char* zugreifen.
- auf ein int32 array darf man per int32* und per char* zugreifen.
- ...

Das sollte die eingangsfrage klären. Andererseits kann man auch mit 
-fno-strict-aliasing kompilieren und alles kann einem egal sein 
(alignment kommt auch noch ins spiel).

Für speicher der über malloc abgeholt wurde, gelten nochmal andere 
regeln, siehe link.

von mh (Gast)


Lesenswert?

aliasing schrieb:
> Für speicher der über malloc abgeholt wurde, gelten nochmal andere
> regeln, siehe link.

Das müsste durch 6.5.6 (der Absatz vor den oben zitierten 
aliasing-Regeln 6.5.7) abgehandelt werden.

von Al Fine (Gast)


Lesenswert?

mh schrieb:
> Was meinst du mit "hier"? In dem Beispiel des TO wird es das sehr wohl.

Wird es nicht. Das wäre doch in C++ gemäß deiner Argumentation 
undefined, also nicht das, was da gemacht wird.

mh schrieb:
> Die Lebenszeit eines Objekt beginnt, wenn der Speicher garantiert zur
> Verfügung steht.

In C++ beginnt (korrekterweise) ein Konstruktor die Lebenszeit eines 
Objekts: Einen von malloc erhaltenen Zeiger zu casten und dann einfach 
Werte zuzuweisen, ist immer undefined.

In C gibt es das Konstrukt aber so nicht. Alles, was im Code des TO 
steht, ist, dass uint16_t-Objekte an bestimmte Stellen geschrieben 
werden. Das ist, glaube ich, kein Zugriff auf die uint8_t.

von mh (Gast)


Lesenswert?

Al Fine schrieb:
> mh schrieb:
>> Die Lebenszeit eines Objekt beginnt, wenn der Speicher garantiert zur
>> Verfügung steht.
>
> In C++ beginnt (korrekterweise) ein Konstruktor die Lebenszeit eines
> Objekts: Einen von malloc erhaltenen Zeiger zu casten und dann einfach
> Werte zuzuweisen, ist immer undefined.
>
> In C gibt es das Konstrukt aber so nicht. Alles, was im Code des TO
> steht, ist, dass uint16_t-Objekte an bestimmte Stellen geschrieben
> werden. Das ist, glaube ich, kein Zugriff auf die uint8_t.

Magst du vielleicht erstmal im Standard nachlesen, bevor du so etwas 
behauptest? Natürlich gibt es auch in C die "Lebenszeit eines Objekts". 
Aus ISO/IEC9899:2017 (das müsste der letzte offizielle C17-Draft sein):
1
6.2.4 Storage durations of objects
2
2) The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it.

von Al Fine (Gast)


Lesenswert?

mh schrieb:
> Magst du vielleicht erstmal im Standard nachlesen, bevor du so etwas
> behauptest? Natürlich gibt es auch in C die "Lebenszeit eines Objekts".

Aber eben nicht explizit durch Konstruktoren und Destruktoren 
eingegrenzt. Wie sollte man sich das vorstellen?
1
void *p = malloc(256); // was lebt hier?
2
uint8_t* p8 = p; // jetzt lebt da ein uint8_t?

von mh (Gast)


Lesenswert?

Al Fine schrieb:
> mh schrieb:
>> Magst du vielleicht erstmal im Standard nachlesen, bevor du so etwas
>> behauptest? Natürlich gibt es auch in C die "Lebenszeit eines Objekts".
>
> Aber eben nicht explizit durch Konstruktoren und Destruktoren
> eingegrenzt. Wie sollte man sich das vorstellen?void *p = malloc(256);
> // was lebt hier?
Nichts! p zeigt auf "allocated memory" mit "no declared type".
> uint8_t* p8 = p; // jetzt lebt da ein uint8_t?
Nein!. p8 zeigt auf den gleichen "allocated memory" mit "no declared 
type".
Erst wenn mit einem geeigneten Lvalue darauf zugegriffen wird  gibt es 
einen "effective type". Ab diesem Zeitpunkt "lebt" dort etwas. Das 
bezieht sich aber auf "allocated memory", hat also nichts mit dem 
ursprünglichen Beispiel des TO zu tun.

von mh (Gast)


Lesenswert?

Achso, das steht übrigens in dem schon genannten Absatz 6.5.6

von Al Fine (Gast)


Lesenswert?

mh schrieb:
> Das bezieht sich aber auf "allocated memory", hat also nichts mit dem
> ursprünglichen Beispiel des TO zu tun.

Das kommt darauf an, wie das malloc() implementiert ist, denke ich.

von mh (Gast)


Lesenswert?

Al Fine schrieb:
> mh schrieb:
>> Das bezieht sich aber auf "allocated memory", hat also nichts mit dem
>> ursprünglichen Beispiel des TO zu tun.
>
> Das kommt darauf an, wie das malloc() implementiert ist, denke ich.

Klar, wenn sich die malloc Implementation nicht an den Standard hält ...

von Al Fine (Gast)


Lesenswert?

mh schrieb:
> Achso, das steht übrigens in dem schon genannten Absatz 6.5.6

Ja, richtig. Ich gebe dir hiermit recht, dass die lifetime der uint8_t 
da schon begonnen hat, deswegen der code undefined ist.

von Al Fine (Gast)


Lesenswert?

Al Fine schrieb:
> mh schrieb:
>> Achso, das steht übrigens in dem schon genannten Absatz 6.5.6
>
> Ja, richtig. Ich gebe dir hiermit recht, dass die lifetime der uint8_t
> da schon begonnen hat, deswegen der code undefined ist.

Ach so: aber eben deshalb, weil dort deshalb kein uint16_t objekt liegen 
kann.

von mh (Gast)


Lesenswert?

Ich hoffe, dass du es richtig verstanden hast. Ich kann allerdings deine 
Argumentation nicht nachvollziehen.

von Al Fine (Gast)


Lesenswert?

mh schrieb:
> Ich hoffe, dass du es richtig verstanden hast. Ich kann allerdings deine
> Argumentation nicht nachvollziehen.

Tja, theoretische Gedankenspiele... Warum sollte man ein Array uint8_t 
deklarieren, wenn man uint16_t speichern will?

von Walter T. (nicolas)


Lesenswert?

Al Fine schrieb:
> Tja, theoretische Gedankenspiele... Warum sollte man ein Array uint8_t
> deklarieren, wenn man uint16_t speichern will?

Beispielsweise oben genannter Klassiker: Weil man in einem STM32F103C8 
einen 8kB-Puffer nicht unbedingt zweimal unterbringen kann und will.

mh schrieb:
> Es ist verboten.
>
> [ sinnvolle Stelle aus dem Standard ]

Den Teil hatte ich gestern übersehen. Damit ist ja eigentlich alles 
geklärt. Ich wechsel auf ein Union.

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.