size_t unter gcc und clang

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 593
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Wohnort: Zürich
Kontaktdaten:

size_t unter gcc und clang

Beitrag von starcow »

Tach meine lieben ZFX'ler :)

Ich habe hier eine etwas seltsame Situation, die ich mir nur halbwegs erklären kann:

(Es wird an keiner Stelle irgendwas includiert)

Code: Alles auswählen

typedef unsigned int size_t;

int main(void)
{
	return _Generic(sizeof(0), size_t: 2, unsigned long long: 1, default: 0);
}
gcc gibt mir 1 zurück - und nicht 2.
Das lässt für mich eigentlich nur den Schluss zu: gcc hat den Typen size_t intern fest als unsigned long long "verdrahtet", resp. arbeitet womöglich erst gar nicht damit.
clang beschwert sich über eine abweichende redefinition, obwohl size_t niergends zuvor im Code als alias resp. typedef definiert wurde.
Interessant ist auch, dass ich size_t unter clang verwenden kann, ohne irgendwo ein typedef von size_t stehen zu haben.

Mein Problem mit size_t:
Es reicht nicht, irgendeinen Typen wie unsigned long long hinter der size_t "Abstraktion" zu verstecken.
Denn sobald eine Variable vom Typen size_t in einem arithmetischen Ausdruck auftaucht, ist es wichtig zu wissen, welche conversations vorgenommen werden und wohin der typ womöglich promoted wird. Denn der standard definiert für size_t eben gerade keine neuen type conversation rules, sondern es gelten nur die usual arithmetic conversions - und die beziehen sich auf die basic types.
Also reicht es leider nicht dieses "Abstraktions-Spiel" von size_t einfach blind mitzuspielen und sich zu sagen "Was auch immer size_t ist, ist Wurst - das macht der Compiler".

Klar, in der Praxis ist das heute sowieso einfach ein unsigned long long. Aber wenn ich mich in meinem Code 100% darauf verlassen muss, kann ich auch gleich direkt jeweils u64 anstelle von size_t verwenden. Dann ist es wenigstens transparent.
Es scheint mir zudem irgendwie auch ein historischer Fehler gewesen zu sein, size_t als unsigned zu definieren. Das zieht jeden arithmetischen Ausdruck in einen Restklassenring rein - und das ist eigentlich fast nie das, was man will.
Ein cast zu i64 ist zudem potentiell ungünstig, da bei einem Wert, der nicht mehr als signed dargestellt werden kann, das Verhalten IB ist.

Oder was denkt ihr dazu?
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
xq
Establishment
Beiträge: 1594
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: size_t unter gcc und clang

Beitrag von xq »

size_t ist ja definiert als "der Typ, welcher die maximale Objektgröße darstellen kann". Im Kontrast dazu gibt es uintptr_t (der Typ, welcher garantiert einen Pointer als Integer aufnehmen kann). Für manche Plattformen gilt, dass sizeof(size_t) != sizeof(uintptr_t) (hallo 8086 mit Segmentierung, hallo AVR mit 24-bit Code Pointer, aber 16-bit size_t).

size_t muss unsigned sein, weil du sonst nur 50% des potentiell verfügbaren Speichers als maximale Objekt-Größe hast. Sprich, eine Struktur oder ein Array können nur 32k statt 64k auf einem 16-bit System groß sein. Unpraktisch, wenn man einen 48k-Speicherblock haben möchte.

Grundlegend halte ich size_t für einen der wichtigsten Typen, und ich rate stark davon ab, irgendwelche "basic types" (int, unsigned long long, ...), weil diese eben keine definierten Größen haben und die Software damit nicht portabel ist (Auf AVR kann int auch nur 8 statt 16 Bit groß sein, je nach Compilerflags/ABI).

Ich seh da ehrlich gesagt wenig Spielraum, das ganze Thema anders zu lösen, und auch moderne Sprachen wie Rust oder Zig haben einen usize-Typ, welcher genau diese Eigenschaften abbilden kann.
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Antworten