Forum: PC-Programmierung Datentyp Speicherverbrauch


von Michael P. (michael_petrich)


Lesenswert?

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
    long id; //<-- 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
int main(int argc, char** argv) {
16
    pthread_t threads[NUM_THREADS];
17
    long i;//<-- Um diese Variable gehts!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
18
    int status_code;
19
   
20
    for(i=0;i<NUM_THREADS;i++){
21
        printf("Creating Thread %d\n",i);
22
        status_code = pthread_create(&threads[i],NULL,PrintHello,(void *)i);
23
        if (status_code){
24
            printf("Error in creating thread - status code is %d\n",status_code);
25
            exit(-1);
26
        }
27
    }
28
    pthread_exit(NULL);
29
        
30
}

von (prx) A. K. (prx)


Lesenswert?

Seit C99 gibt es die Integer-Typen intptr_t und uintptr_t, die geeignet 
sind, einen Pointer vollständig zu enthalten.

von Nils P. (torus)


Lesenswert?

Der saubere Weg wäre, Pointer und Integer nicht zu mischen.
Das geht z.B. indem Du einen Pointer of long übergibst. Hier mal ein 
Beispiel:
1
void *PrintHello(void *threadid) {
2
    long id; 
3
    id = *(long*) threadid;
4
    printf("Hello World! I am thread #%d!\n",id);
5
    pthread_exit(NULL);
6
}
7
8
int main(int argc, char** argv) {
9
    pthread_t threads[NUM_THREADS];
10
    long      thredData[NUM_THREADS];
11
    
12
    long i;
13
    int status_code;
14
   
15
    for(i=0;i<NUM_THREADS;i++){
16
        printf("Creating Thread %d\n",i);
17
        threadData[i] = i;
18
        status_code = pthread_create(&threads[i],NULL,PrintHello,&threadData[i]);
19
        if (status_code){
20
            printf("Error in creating thread - status code is %d\n",status_code);
21
            exit(-1);
22
        }
23
    }
24
    pthread_exit(NULL);
25
        
26
}

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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

von A. S. (Gast)


Lesenswert?

A. K. schrieb:
> printf("%" PRId32 "\n", m);

Auch nicht schlecht...

 Ist PR nun für i, d, x,X oder was es sonst noch so gibt?

von (prx) A. K. (prx)


Lesenswert?

Achim S. schrieb:
>  Ist PR nun für i, d, x,X oder was es sonst noch so gibt?

=> inttypes.h, Google, Bing, ...

von Rolf M. (rmagnus)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.