Sehr gute Frage!
Also wenn man Deklaration und Definition zusammen fasst und überflüssige Klammern entfernt, kommt dabei das hier raus:
int i = (int []) { 0x01 };
Damit bauen wir uns jetzt dieses formschöne Demoprogramm, bei dem ich aus praktischen Gründen mal einen etwas breiteren Integertypen ge-typedef-ed habe:
#include <stdio.h>
typedef unsigned long long ull;
int main(void) {
ull i = (int []) { 0x01 };
ull j = (int *) { 0x01 };
printf("i = %016llX\n", i);
printf("&i = %016llX\n", (ull)&i);
printf("j = %016llX\n", j);
printf("&j = %016llX\n", (ull)&j);
return 0;
}
Übersetzt wird der Klimmbimm hiermit:
clang -std=c99 -O0 -g -Wall -Wextra -Wpedantic foo.c
Als Ausgabe erhält man dann z. B. so etwas:
i = 00007FFE9D10AA7C
&i = 00007FFE9D10AA80
j = 0000000000000001
&j = 00007FFE9D10AA70
Beachte bitte auch, dass du zwei Compilerwarnungen bekommst:
foo.c:7:7: warning: incompatible pointer to integer conversion
initializing 'ull' (aka 'unsigned long long') with an
expression of type 'ull [1]'
foo.c:8:22: warning: incompatible integer to pointer conversion
initializing 'ull *' (aka 'unsigned long long *') with an
expression of type 'int'
Die Variable "i" wird also mit einem anonymen und sog. "flexiblen Array" (also einem Array ohne Größenangabe!) initialisiert, welches gar nicht wirklich existiert (!) aber auf dem Stack ganz in der Nähe von der Variablen "i" eine Adresse hat.
Da es aber von diesem flexiblen Array keinen expliziten Cast (!) in den Integer-Typen von "i" gibt (also ull bzw. unsigned long long), castet der Compiler implizit, und zeigt eine Warnung an.
Die Variable "j" wird hingegen mit einem Zeiger initialisiert, der wiederum auf die Speicherposition "1" zeigt. Aber da es auch hier nur einen Cast von der Konstanten auf einen Zeiger, und keinen Cast (!) von Zeiger auf den Typen von "j" gibt, sagt dir auch hier der Compiler in einer Warnung, dass ein Cast fehlt.
- Im Ergebnis hat jetzt "i" den Wert der Adresse eines nicht-existenten flexiblen Arrays irgendwo auf dem Stack, wobei sich dieser Wert bei jedem Programmstart ändern wird.
- Die Variable "j" hat hingegen bei jedem Programmstart den Wert "1", der einmal explizit in einen Zeiger gecastet wurde, und einmal implizit wieder zurück.
Fazit: Im Grunde genommen liefert dir dein Programm jedes mal eine halbe Adresse (da sizeof(int *) doppelt so groß ist wie sizeof(int) auf 64-Bit Systemen) auf dem Stack, irgendwo in der Nähe deiner Variablen "i" ... und die sieht natürlich recht zufällig bzw. nach "Müll" aus. :)
Noch etwas Zusatzinfo: Mit einer "anonymen Zeichenkette" hat das aber nichts zu tun. Genau genommen kannst du zwar auch in C und C++ anonyme Variablen ohne Namen erzeugen, hast damit aber nur noch bei C++ Zugriff darauf, da C hierfür der syntaktische Zucker fehlt. Diesen "Trick" setzt man oft u. a. bei "selbstregistrierenden Unittests" o. ä. ein.
Außerdem hat nur C++ (und nicht C), eine einzige anonyme Zeichenkette, und zwar heißt die "__func__". Bei C gibt es etwas ähnliches, wie z. B. "__FILE__", aber das sind nur Präprozessor-Makros und keine richtigen "anonymen Zeichenketten", falls du die überhaupt so nennen willst, da ja eigentlich nur die Deklaration, nicht aber der Name, anonym ist.
Deshalb wird "__func__" auch klein geschrieben, weil es im Grunde eine Variable, und "__FILE__" groß, weil es eine Art Makro ist. :)
Naja egal ... wie immer, eine schicke Frage von dir! Ich bin übrigens derjenige, der dir auch immer deine Assembler und Linux-System-Programmierfragen beantwortet hat, aber nicht wundern, weil ich meinen Account mehrmals pro Woche wechsele! Es kommt ja nur auf die Antwortqualität an. Accounts sind belanglos. ;)
Viel Spaß noch mit C! :)