mboost-dp1

GCC 13


Gå til bund
Gravatar #2 - larsp
23. dec. 2022 08:21
Jeg dykkede lige ned i første change log item for C23, https://www.open-std.org/jtc1/sc22/wg14/www/docs/n... "Introduce the nullptr constant"

Jeg må indrømme at jeg er lidt forbløffet over den forvirring der angiveligt er omkring NULL i C, eg.:
Thereby several types are possible for NULL. Commonly used are 0 with int, 0L with long and (void*)0 with void*.
What? Jeg har kun set (void*)0 og kun brugt (void*)0. Hele idéen med NULL er at det er en konstant med værdien 0 af typen vilkårlig pointer, som man kan sammenligne pointere med og assigne til. Hvis man vil have 0 som en integer skriver man da bare 0...??
Another reason to strengthen the definition of null pointer constants in C is the common confusion between a null pointer and a pointer that points to the zero address in the OS, as is suggested by using integer literals such as 0 to express null pointer constants. Also, the fact that on some architectures a null pointer is not necessarily represented with a all-zero bit-pattern always needs special attention when teaching C and is quite surprising for beginners.
Kald mig gerne begynder, men det forstår jeg ikke en bjælde af.

"on some architectures a null pointer is not necessarily represented with a all-zero bit-pattern" ...???? Det ville bryde kompatibilitet med en masse C kode. NULL er ikke en pointer man nogensinde skal følge. Det er til at teste om en pointer har værdien 0.


#define NULL ((void*)0)

int *MyPointer;

void myFunction()
{
if (MyPointer == NULL)
{
MyPointer = makeMyPointer();
}
}

... virker fordi MyPointer har værdien 0 efter C initialisation, og er et meget typisk pattern i C.
Gravatar #3 - larsp
23. dec. 2022 08:35
Og hvis man virkelig var i humør til at tilgå adresse 0, ville man IKKE bruge NULL, men lave nogle grundigt forklarede specifikke typer og definitioner relevante for platformen. Sågar hoppe direkte i assembler, for det vil være noget helt grundlæggende platformkode skrevet og testet af producenten for en given platform.

Det er _meget_ usædvanligt rent faktisk at ville tilgå addresse 0. Det er _meget_ normalt at sammenligne og assigne pointere til NULL. Hvis det er det de mener er forvirringen synes jeg de skyder temmelig meget forbi målet.
Gravatar #4 - arne_v
23. dec. 2022 13:19
#2 og #3

C folket går traditionelt enormt meget op i hvad C standarden definerer og hvad den ikke definerer.

Den nuværende definition af null er meget vag.

Grundliggende siger den at:

en integer konstant med værdi 0 type cast til void* er en null pointer constant
en null pointer constant type cast til en hvilken som helst slags pointer er en null pointer
== mellem to null pointere er sand
== mellem en null pointer og en pointer til data eller pointer til en funktion er altid falsk
stddef.h definerer en NULL makro som er en null pointer constant

Den siger ikke at:
- alle bits er 0 i en null pointer
- at der kun er et bit mønster for null pointer
- typen af NULL er ikke defineret kan være int eller void* [nyt for mig resten er kendt]

Resultatet af enhver assignment fra integer til pointer eller fra pointer til integer udover det definerede er implementations specifikt og compilere kan gøre hvad de vil.

De vil stramme en lile smule op på definitionen: der er en nullptr værdi af type nullptr_t.


Gravatar #5 - arne_v
23. dec. 2022 13:36
larsp (2) skrev:


Also, the fact that on some architectures a null pointer is not necessarily represented with a all-zero bit-pattern always needs special attention when teaching C and is quite surprising for beginners.

Kald mig gerne begynder, men det forstår jeg ikke en bjælde af.

"on some architectures a null pointer is not necessarily represented with a all-zero bit-pattern" ...???? Det ville bryde kompatibilitet med en masse C kode. NULL er ikke en pointer man nogensinde skal følge. Det er til at teste om en pointer har værdien 0.


#define NULL ((void*)0)

int *MyPointer;

void myFunction()
{
if (MyPointer == NULL)
{
MyPointer = makeMyPointer();
}
}

... virker fordi MyPointer har værdien 0 efter C initialisation, og er et meget typisk pattern i C.


C standarden garanterer ikke at en pointer indeholde ene 0 bits.

I praksis gør de det altid.

Der var efter sigende en C implementation tilbage i 80'erne hvor det ikke var tilfældet, men lang tid siden.

Din C kode er OK men p.g.a. en anden krølle.

De fleste tænker på globale variable som memset til 0.

Og det ville ikke garantere at pointere var NULL p.g.a. at null pointere ikke nødvendigvis er 0 bits.

Men standarden siger at aritmetiske typer bliver initialiseret til 0 og at pointer typer bliver initialiseret til null pointer.

Så hvis en C implementation vælger at bruge ene 1 bits til null pointer så skal de initialisere statiske variable uden eksplict initialisering til den værdi.




Gravatar #6 - arne_v
23. dec. 2022 13:38
Der er langt fra diskussion af C standard til diskussion af praktisk brug af C!

:-)
Gravatar #8 - arne_v
26. dec. 2022 00:12
arne_v (5) skrev:

Men standarden siger at aritmetiske typer bliver initialiseret til 0 og at pointer typer bliver initialiseret til null pointer.


I C.

I Fortran 77 er vædien af aritmetiske typer implementation specific (og Fortran 77 har ikke pointere). Så man bør altid eksplicit initialisere.

Jeg har været med til at flytte Fortran 77 kode fra en platform med 0 initalisering (VMS) til en platform med FP NaN initialisering (NOS/VE). Der blev fundet rigtigt mange uinitialiserede variable (et uinitialiseret integer array index med bit mønster fra FP NaN rammer ret langt ude)!

Gravatar #9 - larsp
26. dec. 2022 10:41
arne_v (4) skrev:
Den nuværende definition af null er meget vag.
Er der egentlig nogen? Jeg troede at der (før C23) ikke var noget null pointer koncept i C, kun en makro definition af (void*)0 som egentlig bare er en bekvemmelighed. Man kunne lige så fint have skrevet if (MyPointer == (void*)0) i min kode, i mit hovede.

Men jeg står belært af hvad du skriver, selvom det forekommer mig temmelig skørt at en platform skulle special initialisere pointere til noget der ikke er 0 bits hele vejen. Meningen er jo netop at pointeren ikke er funktionel. Den er tom og ikke assignet til noget brugbart endnu.

... er problemet mon på de obskure ikke-0 NULL platforme, at (void*)0 faktisk er en gyldig og brugbar pointer?

arne_v (4) skrev:
Grundliggende siger den at:
en integer konstant med værdi 0 type cast til void* er en null pointer constant
en null pointer constant type cast til en hvilken som helst slags pointer er en null pointer
== mellem to null pointere er sand
== mellem en null pointer og en pointer til data eller pointer til en funktion er altid falsk
stddef.h definerer en NULL makro som er en null pointer constant

Den siger ikke at:
- alle bits er 0 i en null pointer
Er der ikke en selvmodsigelse her? Mellem "en integer konstant med værdi 0 type cast til void* er en null pointer constant" og "Den siger ikke at: - alle bits er 0 i en null pointer"
Gravatar #10 - larsp
26. dec. 2022 10:57
arne_v (7) skrev:
https://c-faq.com/null/machexamp.html
Gys. Jeg er glad for at jeg "kom til verdenen" efter computere i det store og hele havde lagt sig fast på at køre med 8 / 16 / 32 bit uden alle mulig skæverter :)

arne_v (5) skrev:
Men standarden siger at aritmetiske typer bliver initialiseret til 0 og at pointer typer bliver initialiseret til null pointer.

Det er nok den paragraf jeg har misset. Jeg tænkte at globale pointere uden angivet værdi som en selvfølge blev lagt i BSS, som jo bliver memset til 0 ved C init, ligesom alle andre tilsvarende globale variable.

Er hele TEXT, DATA, BSS, HEAP ... STACK segment strukturen egentlig spec'et i en standard eller er det bare noget der blev kutyme hen af vejen? Lad mig gætte at det er POSIX afledt.
Gravatar #11 - arne_v
26. dec. 2022 14:16
larsp (9) skrev:
arne_v (4) skrev:
Den nuværende definition af null er meget vag.
Er der egentlig nogen? Jeg troede at der (før C23) ikke var noget null pointer koncept i C, kun en makro definition af (void*)0 som egentlig bare er en bekvemmelighed. Man kunne lige så fint have skrevet if (MyPointer == (void*)0) i min kode, i mit hovede.


En opsummering af hvad standarden (C11) siger kom lidt senere i posten.

larsp (9) skrev:

Men jeg står belært af hvad du skriver, selvom det forekommer mig temmelig skørt at en platform skulle special initialisere pointere til noget der ikke er 0 bits hele vejen. Meningen er jo netop at pointeren ikke er funktionel. Den er tom og ikke assignet til noget brugbart endnu.


Ja. Men en "ikke brugbar" marker behøver ikke være ene 0 bits.


larsp (9) skrev:

... er problemet mon på de obskure ikke-0 NULL platforme, at (void*)0 faktisk er en gyldig og brugbar pointer?


(void*)0 skal konverteres til det bit mønster der betyder ikke brugbar per standard. Men en lille assembler funktion kunne returnere en pointer til noget der på det pågældene OS var ene 0 bit.

larsp (9) skrev:

arne_v (4) skrev:
Grundliggende siger den at:
en integer konstant med værdi 0 type cast til void* er en null pointer constant
en null pointer constant type cast til en hvilken som helst slags pointer er en null pointer
== mellem to null pointere er sand
== mellem en null pointer og en pointer til data eller pointer til en funktion er altid falsk
stddef.h definerer en NULL makro som er en null pointer constant

Den siger ikke at:
- alle bits er 0 i en null pointer
Er der ikke en selvmodsigelse her? Mellem "en integer konstant med værdi 0 type cast til void* er en null pointer constant" og "Den siger ikke at: - alle bits er 0 i en null pointer"


Hvis det type cast altid beholder bit mønster så er det en modsigelse, men det siger C standard ikke noget om. Hvis NULL ikke er ene 0 bit så skal der ændres bit møster ved det cast.

Der er gode grunde til at NULL normalt er ene 0 bits. Det er møghamrende besværligt for compileren hvis de ikke er.
Gravatar #12 - arne_v
26. dec. 2022 14:39
larsp (10) skrev:
arne_v (7) skrev:
https://c-faq.com/null/machexamp.html
Gys. Jeg er glad for at jeg "kom til verdenen" efter computere i det store og hele havde lagt sig fast på at køre med 8 / 16 / 32 bit uden alle mulig skæverter :)


8/16/32/64 bit two's complement integers, 32/64 bit IEEE floating point, 8 bit bytes og byte addressering er blevet de facto standard.

I ganmle dage var det mere "spændende".

CDC med 60 bit one's complement integers, 60/120 bit floating point, 6/12/8 bit characters og word adressering.

Der var masser af maskiner med 36 bit integers, forskellige 6/7/8/9 bit characters og word adressering (diverse IBM, DEC-10 og DEC-20, Univac 1100, Honeywell etc.).

VAX havde 32/64 bit floating point men ikke IEEE (IEEE floating point var ikke opfundet da VAX blev introduceret).

Samme med original IBM mainframe - 32/64 bit floating point non-IEEE (og 16 baseret ikke 2 baseret !).

larsp (10) skrev:

arne_v (5) skrev:
Men standarden siger at aritmetiske typer bliver initialiseret til 0 og at pointer typer bliver initialiseret til null pointer.

Det er nok den paragraf jeg har misset. Jeg tænkte at globale pointere uden angivet værdi som en selvfølge blev lagt i BSS, som jo bliver memset til 0 ved C init, ligesom alle andre tilsvarende globale variable.

Er hele TEXT, DATA, BSS, HEAP ... STACK segment strukturen egentlig spec'et i en standard eller er det bare noget der blev kutyme hen af vejen? Lad mig gætte at det er POSIX afledt.


C standarden siger intet om de segmenter.

Stort set alle har vel konvergeret mod en ihvertfald lignende model.

Jeg tror ikke at den er POSIX specificeret. POSIX er meget "what" og næsten intet "how".

Gravatar #13 - arne_v
26. dec. 2022 14:53
Med hensyn til byte adressering vs word adressering skal man gøre sig klart at selvom en addresse idag nummererer bytes, så kan man ikke nødvendigvis lave integer og floating point operationer på vilkårlige adresser.

x86-64 er nem - alt virker.

Men på mange RISC CPU vil en operation på en ikke aligned adresse give en fault.

På Solaris/SPARC crasher ens program (segmentation fault hvis jeg husker rigtig).

VMS/Itanium fanger fault, loader 2 units, shifter data omkring og komme til det rigtige resultat, men det kører en faktor 300 langsommere (!!).

Så:

char *p;
int v;
p = ...;
v = *((int *)p);

er kun sikker hvis man ved at p peger på et multipla af sizeof(int).

Ellers er det:

memcpy(&v, p, sizeof(int));

Ville lige nævne det da jeg har haft rigtigt mange problemer med det på Solaris/SPARC.
Gravatar #14 - arne_v
26. dec. 2022 17:56
#12

Der er iøvrigt masser af leftovers fra den gang i C.

Right shift af negative signed integers er implementations specifik. Fordi C skal understøtte både one's complement og two's complement.

Oktale konstanter. I en 8/16/32 bit verden har ingen brug for oktale konstanter - alle bruger hex konstanter (udover decimal naturlighvis). Men i en verden med 6 bit characters og 18 bit adresser giver oktaler en vis mening. 000-077 fremfor 0x00-0x3F (mens 0000-0377 vs 0x00-0xFF er mindre oplagt).
Gå til top

Opret dig som bruger i dag

Det er gratis, og du binder dig ikke til noget.

Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.

Opret Bruger Login