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);
}
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?