Forum: PC-Programmierung Struct: gleiche Daten in verschiedenen Variablen


von Rene K. (xdraconix)


Lesenswert?

Ich habe folgendes Struct:

Ich möchte in R G B die gleichen Variablen stehen haben wie in URGB. Wie 
stelle ich das am dümmsten an? Kann ich einen Teil des Speicherbereichs 
von URGB auf R mappen? Oder muss ich dies durch eine Funktion laufen 
lassen?

Sprache ist C.
1
typedef struct
2
 {
3
   uint8_t R;
4
   uint8_t G;
5
   uint8_t B;
6
   uint32_t URGB;   
7
 }  RGBVal;

Liebe Grüße René

von Wilhelm M. (wimalopaan)


Lesenswert?

Rene K. schrieb:
> Ich habe folgendes Struct:
>
> Ich möchte in R G B die gleichen Variablen stehen haben wie in URGB.

Du meinst Werte.

> Wie
> stelle ich das am dümmsten an?

Das Stichwort heißt: union

von DPA (Gast)


Lesenswert?

Naja, das geht, ab c11, zwar in der regel schon:
1
typedef struct {
2
  union {
3
    struct {
4
       uint8_t U;
5
       uint8_t R;
6
       uint8_t G;
7
       uint8_t B;
8
     };
9
     uint32_t URGB;
10
  };
11
} RGBVal;

Ist aber eigentlich UB. In clang und gcc sollte es gehen. Der Wert in 
URGB ist dann aber von der endianness abhängig.

von Wilhelm M. (wimalopaan)


Lesenswert?

DPA schrieb:

> Ist aber eigentlich UB.

In C ist type-punning explizit erlaubt.
In C++ ist das Zugreifen auf ein nicht-aktives Element UB (es sei den: 
common-initial subsequence)

von Oliver S. (oliverso)


Lesenswert?

Rene K. schrieb:
> Oder muss ich dies durch eine Funktion laufen
> lassen?

Das wäre das sauberste. Im Struct nur die drei RGB-Werte abspeichern, 
und dazu

uint32_t convertToURGB(RGBVal* RGB);

und wenn es sein muß, noch eine Funktion für die andere Richtung.

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> Rene K. schrieb:
>> Oder muss ich dies durch eine Funktion laufen
>> lassen?
>
> Das wäre das sauberste.

Wie gesagt: in C ist der Ansatz mit der union absolut legal und explizit 
für type-punning vorgesehen. Deswegen nicht "unsauber" (was auch immer 
das heißen mag), solange man die Endianness außer Acht lassen kann 
(keine Serialisierung).

Der Ansatz mit (inline) Funktion und shifts löst auch das Problem.

Und memcpy geht auch noch, verkapselt in einer (inline) Funktion.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Oliver S. schrieb:
>> Rene K. schrieb:
>>> Oder muss ich dies durch eine Funktion laufen
>>> lassen?
>>
>> Das wäre das sauberste.
>
> Wie gesagt: in C ist der Ansatz mit der union absolut legal und explizit
> für type-punning vorgesehen.

Nein, vorgesehen war er dafür eigentlich nicht. Und die Erklärung, dass 
man sie dafür verwenden könnte, steht nur in einer nicht normativen 
Fußnote.
Dafür steht im normativen Teil aber das mit der common initial sequence 
von zwei Strukturen (wie in C++) als "one special guarantee" drin.

von A. S. (Gast)


Lesenswert?

Rene K. schrieb:
> Ich möchte in R G B die gleichen Variablen stehen haben wie in URGB.

Was möchtest Du erreichen?

In den meisten Fällen ist es straight, ein Format zu nehmen und das 
andere per Funktionen bei Bedarf zu konvertieren. Kostet heute auch 0 
Overhead.

Für Zuweisungen in einer Anweisung reicht das rgb-struct. Eine 
Verwendung als Skalar ist für das u32 ja kaum sinnvoll (+x oder *2). 
Einzig der Vergleich ist damit einfacher. Wenn das nicht oft vorkommt, 
nimm das RGB struct und sage, was Du mit dem u32 machen möchtest.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Oliver S. schrieb:
>>> Rene K. schrieb:
>>>> Oder muss ich dies durch eine Funktion laufen
>>>> lassen?
>>>
>>> Das wäre das sauberste.
>>
>> Wie gesagt: in C ist der Ansatz mit der union absolut legal und explizit
>> für type-punning vorgesehen.
>
> Nein, vorgesehen war er dafür eigentlich nicht. Und die Erklärung, dass
> man sie dafür verwenden könnte, steht nur in einer nicht normativen
> Fußnote.

Der normative Text ist:

"A postfix expression followed by the . operator and an identifier 
designates a member of a structure
or union object. The value is that of the named member,107) and is an 
lvalue if the first expression is
an lvalue. If the first expression has qualified type, the result has 
the so-qualified version of the type
of the designated member."

Die nicht-normative Fußnote erläutert den nicht-normativen Begriff 
"type-punning".

Also: "type-punning" ist also explizit erlaubt, auch wenn der Begriff 
nur in der Fußnote fällt.

> Dafür steht im normativen Teil aber das mit der common initial sequence
> von zwei Strukturen (wie in C++) als "one special guarantee" drin.

Aber darum geht es doch hier gar nicht.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Der normative Text ist:
>
> "A postfix expression followed by the . operator and an identifier
> designates a member of a structure or union object. The value is that of
> the named member,107) and is an lvalue if the first expression is
> an lvalue. If the first expression has qualified type, the result has
> the so-qualified version of the type of the designated member."

Dort sehe ich nirgends eine explizite Erlaubnis, ein anderes Element als 
das zuletzt geschriebene zu lesen.

> Die nicht-normative Fußnote erläutert den nicht-normativen Begriff
> "type-punning".

Die Fußnote beschreibt es komplett und gibt in Klammern an, dass man das 
"type punning" nennt.

Das ist für mich kein Zeichen dafür, dass unions wie du sagst explizit 
dafür vorgesehen wären, sondern eher, dass es auf Grund häufiger Nutzung 
eben akzeptiert wird.

>> Dafür steht im normativen Teil aber das mit der common initial sequence
>> von zwei Strukturen (wie in C++) als "one special guarantee" drin.
>
> Aber darum geht es doch hier gar nicht.

Warum ist das eine "special guarantee", wenn type punning doch sowieso 
der angedachte Zweck sein soll?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Der normative Text ist:
>>
>> "A postfix expression followed by the . operator and an identifier
>> designates a member of a structure or union object. The value is that of
>> the named member,107) and is an lvalue if the first expression is
>> an lvalue. If the first expression has qualified type, the result has
>> the so-qualified version of the type of the designated member."
>
> Dort sehe ich nirgends eine explizite Erlaubnis, ein anderes Element als
> das zuletzt geschriebene zu lesen.

Weil das Konzept des active-members in C nicht gibt im Gegensatz zu C++. 
Deswegen reicht es hier aus, einfach zu schreiben, dass der Wert der 
union dem Wert das benutzen Elementes entspricht (Achtung: es kann auch 
hier trap-representations geben).

> Die Fußnote beschreibt es komplett und gibt in Klammern an, dass man das
> "type punning" nennt.
>
> Das ist für mich kein Zeichen dafür, dass unions wie du sagst explizit
> dafür vorgesehen wären, sondern eher, dass es auf Grund häufiger Nutzung
> eben akzeptiert wird.

Natürlich war es ganz ursprünglich da, um Speicher zu sparen.
Die Formulierung ist eine Klarifizierung gegenüber C89.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Natürlich war es ganz ursprünglich da, um Speicher zu sparen.

Es war (und ist) eigentlich dafür da, Variablen erstellen zu können, die 
ihren Typ je nach Situation wechseln können, also eine einfache Art von 
variant-Typ.

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.