Moin liebe Gemeinde,
Ich mache in Vorbereitung fuer ein Labor Uebungsaufgaben zum Thema
Multithreading. Der Code der Aufgabe am Ende. Problem war, dass der
Compiler sich ueber das Casting von Integer zu einem Pointer um
umgedreht beschwert hatte. Die Funktion PrintHello muss aber mit
Pointern aufgerufen werden, weil es so in pthread_create gefordert wird.
Nachdem ich dann die Integer-Variablen mit "long" anstatt "int"
deklariert habe, gings Problemlos.
Nach ein wenig Recherche habe ich dann rausgefunden, dass der
Speicherbedarf eines Pointer immer (?!?) gleich der Wortbreite der CPU
ist, in meinem Fall also 64Bit. Eine Integervariable aber auch abhaengig
von der Wortbreite ist.
Je nach Quelle findet man jetzt unterschiedliche Angaben:
- Integer int hat die Wortbreite der CPU/OS (beisst sich mit meiner
Beobachtung)
- Integer hat 16/32/64 Bit ?!?
- int und long haben den gleichen Speicherplatzbedarf (32Bit)
- Haengt vom Compiler bzw. dessen Standard ab
Ich habe stark das Gefuehl, dass die Quellen immer untern Tisch fallen
lassen, um was fuer eine CPU/OS bzw. dessen Wortbreite handelt.
Also wenn es stimmt, dass der Pointer bei einem 64Bit OS auch 64Bit hat,
dann muesste eine int bei mir 32Bit haben und eine long 64Bit.
Warum ich mir da jetzt so einen Kopf mache? Ich ueberlege gerade wie das
mit der Portabilitaet (nennt man das so?) auf ein anderes System (oder
einfach anderen Rechner) aussieht. Wenn ich immer "von Hand" die
Variablendeklaration aendern muesste, waere das ja recht doof. Noch
doofer natuerlich, wenn sowas beim Test garnicht auffaellt (alle haben
ein 64Bit-System), man ein "Produkt" fertig hat und es beim "Kunden"
nicht laeuft.
Wie bekommt man solche Faelle in Griff, sodass zB. der Speicherbedarf
einer Integer (die hier ja quasi nur als Laufvariable dient) immer der
eines Pointers entspricht?
Vielen Dank
Michael
1
#include<cstdlib>
2
#include<pthread.h>
3
#include<stdlib.h>
4
#include<stdio.h>
5
6
#define NUM_THREADS 5
7
8
void*PrintHello(void*threadid){
9
longid;//<-- Um diese Variable gehts!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10
id=(long)threadid;
11
printf("Hello World! I am thread #%d!\n",id);
12
pthread_exit(NULL);
13
}
14
15
intmain(intargc,char**argv){
16
pthread_tthreads[NUM_THREADS];
17
longi;//<-- Um diese Variable gehts!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Michael P. schrieb:> Nach ein wenig Recherche habe ich dann rausgefunden, dass der> Speicherbedarf eines Pointer immer (?!?) gleich der Wortbreite der CPU> ist, in meinem Fall also 64Bit.
Die Breite eines Pointers entspricht meist mindestens der Adressbreite
der logischen Adresse im gewählten Programmiermodell eines Prozesses.
Viel genauer wirds nicht, und nicht einmal das ist sicher, s.u.
Bei x86-ern gibts allerlei Programmiermodelle, die teilweise parallel
von verschiedenen Prozessen genutzt werden:
1
16-Bit Pointer zzgl 16-Bit Segmentinfo separat
2
32-Bit Pointer aus 16-Bit Offset und 16-Bit Segmentinfo
3
32-Bit Pointer flat
4
32-Bit Pointer zzgl 16-Bit Segmentinfo separat
5
48-Bit Pointer aus 32-Bit Offset und 16-Bit Segmentinfo
6
64-Bit Pointer flat
7
64-Bit Pointer zzgl 16-Bit Segmentinfo separat
Die Adressieung von Code und von Daten kann (konnte) dabei verschiedene
solche Adressmodelle nutzen, also Pointer auf Code breiter (32 Bit) als
Pointer auf Daten (16 Bit).
> Eine Integervariable aber auch abhaengig von der Wortbreite ist.
Und von der Laune der Entwickler des APIs des gewählten
Programmiermodells.
> Ich habe stark das Gefuehl, dass die Quellen immer untern Tisch fallen> lassen, um was fuer eine CPU/OS bzw. dessen Wortbreite handelt.
Dein Gefühl trügt dich nicht. Trotz gleicher CPU ist im 64-Bit Modus der
Typ "long" in Windows anders als in Linux.
Siehe https://de.wikipedia.org/wiki/64-Bit-Architektur#Programmiermodell> Also wenn es stimmt, dass der Pointer bei einem 64Bit OS auch 64Bit hat,> dann muesste eine int bei mir 32Bit haben und eine long 64Bit.
Könnte man so machen. Allerdings hatte Microsoft vmtl die Sorge, dass
99% aller Anwendungen hätten vollständig überarbeitet werden müssen,
wenn dem so wäre. Folglich ist "long" In Win64 auch nur 32 Bit gross.
> Wie bekommt man solche Faelle in Griff,
Siehe types.h. Wenn du 64 Bits brauchst, schreib sowas wie int64_t. Das
geht vom 8-Bitter AVR bis zum 64-Bitter.
Die ganzen Typen mit Größenangaben (int32 etc) bringen dir nichts bei
printf (oder anderen variadic funktions). Du musst wissen, ob Du %lx
oder %x brauchst, wenn sie unterschiedlich sind.
Achim S. schrieb:> Die ganzen Typen mit Größenangaben (int32 etc) bringen dir nichts bei> printf (oder anderen variadic funktions). Du musst wissen, ob Du %lx> oder %x brauchst, wenn sie unterschiedlich sind.
Für wie doof hältst du die Standardisierer denn?
printf("%" PRId32 "\n", m);
Michael P. schrieb:> von der Wortbreite ist.> Je nach Quelle findet man jetzt unterschiedliche Angaben:> - Integer int hat die Wortbreite der CPU/OS (beisst sich mit meiner> Beobachtung)
Nach ISO C sollte int die natürliche Wortbreite haben, muss aber
nicht. Das Problem ist, dass bei 64-Bit-Prozessoren dann die Typen
ausgehen, denn es gibt nur zwei Integer-Typen, die kleiner als int sein
dürfen, nämlich char und short. Das reicht dann nicht mehr für 8, 16 und
32 Bit. Also bleibt auch bei 64-Bit-Plattformen int in der Regel 32 Bit
breit.
> - Integer hat 16/32/64 Bit ?!?
Wenn du mit "Integer" int meinst, muss dieser mindestens 16 Bit breit
sein, darf aber beliebig breiter sein. Das muss auch keine Zweierpotenz
sein, sondern dürfen auch 48 oder 25 Bit sein.
> - int und long haben den gleichen Speicherplatzbedarf (32Bit)
long muss mindestens 32 Bit und mindestens so breit wie int sein. Darf
aber auch beliebig größer sein.
> - Haengt vom Compiler bzw. dessen Standard ab
Ja.
> Warum ich mir da jetzt so einen Kopf mache? Ich ueberlege gerade wie das> mit der Portabilitaet (nennt man das so?) auf ein anderes System (oder> einfach anderen Rechner) aussieht.
Das ist sehr gut. Wenn man sich darüber nämlich von Anfang an Gedanken
macht, ist eine Portierung nachher recht schmerzfrei möglich. Wenn man
sich darum überhaupt nicht kümmert, kann es später extrem aufwändig
werden.
> Wenn ich immer "von Hand" die Variablendeklaration aendern muesste, waere> das ja recht doof.
Man muss sich nur vor Augen halten, dass folgendes gilt:
char ist mindestens 8 Bit
short ist mindestens 16 Bit
int ist ebenfalls mindestens 16 Bit (auf POSIX-Systemen mindestens 32
Bit)
long ist mindestens 32 Bit
long long ist mindestens 64 Bit
Und dann gibt's noch die schon angesprochenen Typen [u]intX_t (X=8, 16,
32 oder 64) für exakte Breiten, wie z.B. uint16_t ein vorzeichenloser
16-Bit-Typ ist. Exakte Breiten braucht man aber normalerweise nur zum
Ansprechen vor HW-Registern oder für Kommunikation in einem Binärformat.
Programmintern ist man meist eher darauf aus, den gewünschten
Wertebereich entweder mit minimalem Speicher- oder minimalem
Rechenzeitaufwand zu bekommen. Dafür gibt's auch Typ-Aliases, nämlich
[u]int_leastX_t für den kleinstmöglichen Typen, der mindestens X bits
breit ist und [u]int_fastX_t für einen möglichst Rechenzeit-effizienten
Typen mit mindestens X Bit.
> Wie bekommt man solche Faelle in Griff, sodass zB. der Speicherbedarf> einer Integer (die hier ja quasi nur als Laufvariable dient) immer der> eines Pointers entspricht?
Am besten, indem man gar nicht zwischen Pointern und Integern hin und
her konvertiert. In der Regel braucht man das nicht.
A. K. schrieb:> Seit C99 gibt es die Integer-Typen intptr_t und uintptr_t, die geeignet> sind, einen Pointer vollständig zu enthalten.
Hier geht's aber um den umgekehrten Fall: Ein Integer-Typ, desen Wert
ein Zeiger vollständig enthalten können soll. Das ist soweit ich weiß
für diese beiden Typen nicht garantiert.
Rolf M. schrieb:> Hier geht's aber um den umgekehrten Fall: Ein Integer-Typ, desen Wert> ein Zeiger vollständig enthalten können soll.
Dafür sollte es ptrdiff_t tun.