2009-06-18 9 views
15

Wenn ich malloc benutze und ähnliche Speichermanipulationen mache, kann ich mich darauf verlassen, dass sizeof (char) immer 1 ist?Ist es notwendig, beim Manipulieren des Speichers mit sizeof (char) zu multiplizieren?

Zum Beispiel muss ich Speicher für N Elemente des Typs char reservieren. Ist Multiplikation mit sizeof(char) notwendig:

char* buffer = malloc(N * sizeof(char)); 

oder kann ich mich verlassen sizeof (char) immer 1 sein und lassen Sie die Multiplikation

char* buffer = malloc(N); 

ich völlig verstehen, dass sizeof während der Kompilierung ausgewertet wird und dann dem Compiler könnte sogar die Multiplikation kompilieren und so wird die Leistungseinbuße minimal und höchstwahrscheinlich Null sein.

Ich frage hauptsächlich über Code Klarheit und Portabilität. Ist diese Multiplikation überhaupt notwendig für char Typ?

Antwort

6

Während es ist nicht notwendig, halte ich es für eine gute Praxis in der sizeof (char) zu verlassen, weil sie den Code besser lesbar und vermeidet die Verwendung einer magischen Zahl macht. Auch wenn der Code später geändert werden muss, so dass anstelle eines char ist es die Größe von etwas in einen Zeiger für das Objekt mallocing, ist es einfacher, als den Code zu ändern, wenn Sie nur eine „1“ haben.

+6

Dieses Argument "Leichtigkeit des Änderns des Codes" ist Bulle. 'sizeof()' ist 8 Zeichen.Es muss hinzugefügt werden, weil jemand 'sizeof (char)' nicht geschrieben hat und dann der Typ, der in 'wchar_t' geändert wurde, niemandem mehr Karpaltunnel gibt, und wenn Sie betroffen sind, sollten Sie 'sizeof * buf' trotzdem verwenden weil es dir sogar _less_ tippt. –

+0

@ChrisLutz, Ich schaue auf den C11-Standard und ich sehe keine Klausel die speziell sagt 'sizeof (char)' ist eins. Nach [wikipedia] (http://en.wikipedia.org/wiki/C_data_types#Basic_types) kann es alles sein: _ "Zum Beispiel können alle Typen 64-Bit sein" _. Könntest du mir bitte sagen, wo im Standard es so steht? – Shahbaz

+4

@Shahbaz - 6.5.3.4 Absatz 4: "Wenn' sizeof' auf einen Operanden vom Typ 'char',' unsigned char' oder 'signed char' (oder eine qualifizierte Version davon) angewendet wird, ist das Ergebnis 1. " So war es immer, so wird es immer sein. Das "char" ist das "Byte" von C. Aus der Sprachperspektive ist es egal, wie viele Bits ein "char" ist, es ist die kleinste vollständige Einheit und alle "sizeof" -Werte sind in Form von "char" angegeben 's eher als" Bytes "(die im C-Standard nicht richtig existieren). Wenn alle Typen 64-Bit sind, 'sizeof (char) == sizeof (kurz) == sizeof (int) == sizeof (lang) == 1', nicht 8. –

6

Es ist nicht notwendig. Siehe here (zum Beispiel).

sizeof(char) wird durch die C-Standard definiert immer (Byte) sein. Beachten Sie, dass, weil sizeof eine Anzahl von Bytes zurückgibt, die Anzahl der Bits pro Byte irrelevant ist (und in praktischer Hinsicht ist es trotzdem 8).

14

sizeof(char) ist immer 1, egal welche Art von Speichermanipulation Sie tun.

sizeof(TCHAR) kann jedoch je nach Compileroptionen variieren.

+0

Ich bin kein Experte, aber wird die Größe eines Charakters in Unicode-Situationen nicht größer? –

+4

@Shadow, nein. In diesem Fall wird normalerweise der breite Zeichentyp wchar_t anstelle von char verwendet. Das Microsoft-spezifische TCHAR-Geschäft ist eine Möglichkeit, Code zu schreiben, der für breite oder schmale Zeichen kompiliert werden kann. Es ist nicht klar, ob das eine gute Idee war oder nicht. – RBerteig

+0

@RBertig: Ich würde sagen, es ist klar, dass es eine schlechte Idee ist. Der einzige Grund, nicht-breite 'char'-Zeichenfolgen unter Windows zu verwenden, besteht darin, portablen Code zu verwenden, der auf anderen, mehr standardkonformen Systemen (POSIX) funktioniert. Sobald du 'TCHAR' schreibst, ist dein Code bereits mit Windows-spezifischen Dingen verschmutzt und du kannst genauso gut ihre umfangreichen Funktionen und Typen direkt verwenden. Es ist nicht so, dass irgendjemand ** will, dass ** ihre Programme brechen, sobald der Benutzer versucht, einen Dateinamen mit Zeichen ohne Zeichensatz darin zu öffnen. –

27

Per Definition ist sizeof (char) immer gleich 1. Ein Byte ist die Größe eines Zeichens in C, unabhängig von der Anzahl der Bits in einem Byte (8 auf der allgemeinen Desktop-CPU).

Das typische Beispiel, wo ein Byte nicht 8 Bits ist, ist die PDP-10 und andere alte, Mini-Computer-ähnliche Architekturen mit 9/36 Bits. Aber Bytes, die nicht 2^N extrem selten sind immer ich glaube

Auch ich denke, das ist besser Stil ist:

char* buf1; 
double* buf2; 

buf1 = malloc(sizeof(*buf1) * N); 
buf2 = malloc(sizeof(*buf2) * N); 

, weil es funktioniert, was auch immer der Zeiger-Typ ist.

+0

Ich dachte, dass die Definition von 1Byte = 8 Bits ist. Hast du ein Beispiel, wo dies nicht zutrifft? – AlexDrenea

+6

Die Definition von 1 Byte ist N Bits, wobei N maschinenabhängig ist. Nicht alle Maschinen haben 8 Bits/Byte (obwohl es nicht viele heutzutage gibt) –

+11

@AlexDrenea: Heute werden Sie normalerweise nur 8 Bit-Bytes treffen. Aber die Definition eines Bytes variiert und ist nicht an heutige Architekturen gebunden, weil es Systeme mit 9 Bit Bytes und sogar 36 Bit Bytes gab. Wenn Sie sicher sein wollen, verwenden Sie den ISO Begriff "Oktett" anstelle von Byte. – OregonGhost

10

Ich halte es für eine Art von anti-pattern. Es signalisiert, dass der Programmierer nicht genau wusste, was er tat, was den Rest des Codes sofort in zweifelhaftes Licht tauchte.

Zugegeben, es ist nicht (zitiert Wikipedia) "ineffektiv", aber ich finde es "weit von optimal". Zur Laufzeit kostet es nichts, aber es füllt den Code mit unnötigem Müll und signalisiert, dass es jemand für nötig hält.

Beachten Sie auch, dass der Ausdruck nicht als Funktionsaufruf analysiert wird: sizeof ist keine Funktion. Du rufst keine Funktion an und übergibst das magische Symbol char.Sie wenden den integrierten unären Präfixoperator sizeof auf einen Ausdruck an, und Ihr Ausdruck ist in diesem Fall eine Umwandlung in den Typ char, der in C als (char) geschrieben wird.

Es ist durchaus möglich, und hoch, wann immer möglich zu empfehlen, sizeof auf anderen Ausdrücke zu verwenden, es wird dann die Größe des Wertes des Ausdrucks ergibt:

char a; 
printf("A char's size is %u\n", (unsigned int) sizeof a); 

Dies wird 1, immer, auf all konformen C drucken Implementierungen.

ich mit David Cournapeau auch stark einverstanden und betrachten die Nameart -in einem malloc() -Aufruf Wiederholung auch irgendwie ein Anti-Muster sein.

Statt

char *str; 

str = malloc(N * sizeof (char)); 

, dass viele eine N-Zeichen-Kapazität String-Puffer zuzuweisen schreiben würde, würde ich gehen mit

char *str; 

str = malloc(N * sizeof *str); 

Oder (für Strings nur) auslassen die sizeof als per oben, aber das ist natürlich allgemeiner und funktioniert genauso gut für jede Art von Zeiger.

+2

stimme ich nicht zu. Wenn Sie es weglassen, müssen Sie (und alle, die Ihren Code lesen) daran denken, dass dies ein Sonderfall ist und diesen als solchen erkennen. Das erhöht die kognitive Belastung. Manchmal ist mehr Code besser. –

+1

Ja, sizeof ist keine Funktion - aber für mich liest es sich einfacher, wenn Sie es wie eins behandeln. Es sei denn, Sie kennen einen Fall, in dem die zusätzlichen Klammern die Ausgabe ändern? –

+2

@Michael Carman - Es ist normalerweise ein Sonderfall, weil Sie oft Strings zuweisen und damit arbeiten, während Sie, wenn Sie ein Array von Ints machen, es für jeden Zweck verwenden können. Wir müssen Strings anders behandeln als willkürlich typisierte Arrays, und ich finde das Fehlen von 'sizeof (type)' in einem 'malloc()', um eine schöne Erinnerung daran zu sein. –

-4

Mit sizeof (char) wird Ihr Code lesbarer und portabler.

Auf x86 wissen wir alle, dass ein Zeichen 1 Byte ist. Aber das explizite Niederschreiben macht deine Absichten klarer, was immer eine gute Sache ist.

Auch, was ist, wenn Ihr Code auf einer anderen Plattform, wo ein Zeichen ist nicht 1 Byte gesetzt wird. Was wäre, wenn ein Charakter nur 4 Bits hätte?

Einverstanden, es ist nicht notwendig, aber es verlangsamt nicht Ihre Laufzeit und es wird sich auszahlen in diesem seltenen Fall müssen Sie Ihren Code auf eine andere Architektur portieren.

+0

Das, worum ich gefragt habe. Offiziell ist char der kleinste adressierbare Speicherbaustein, der nicht auf 8 Bit beschränkt ist. Die Frage ist, ob der malloc und alle anderen ähnlichen Sachen in Zeichen arbeiten, nicht in 8-Bit-Bytes. – sharptooth

+1

Ahh ok, dann ja, malloc funktioniert in Bezug auf Zeichen, nicht Bytes. malloc (1) gibt 1 Zeichen großen Speicherblock zurück. – samoz

+2

-1 Ihre Antwort ist sachlich falsch. 'sizeof (char)' ist _always_ 1. Wenn ein 'char' nur 4 Bits ist, dann sind 4 Bits 1 Byte auf dieser Plattform, aber 'sizeof (char)' ist definiert als 1 (Byte), egal wie viele Bits ist es. Das von Ihnen besprochene Problem wird mit dem Makro 'CHAR_BITS' behandelt. –

3

Noch etwas zu beachten ist, dass der Compiler statisch weiß, dass der Wert von sizeof (char) 1 ist und dass die Multiplikation einer Zahl mit einer statischen 1 bedeutet, dass die Multiplikation nicht durchgeführt werden muss; der Compiler wird es optimieren. Leistungsbedenken sollten aus diesen Gründen nicht in Betracht gezogen werden.

3

Von "New C Standard. Ein wirtschaftlicher und kultureller Kommentar".

  1. Statistik: 2,0% sizeof stammen aus char und 1,5% - von unsigned char. Seite 1033 in 1.2 Version des Buches.
  2. Seite 1037.

Die Anzahl der Bits in der Darstellung eines Zeichentyps ist irrelevant.Per Definition ist die Nummer von Bytes in Byte ein Zeichentyp eins.

Codierrichtlinien Entwickler manchmal verknüpfen ein Byte wie immer acht Bits enthalten. Auf Hosts, bei denen der Zeichentyp 16 Bit ist, kann dies zu der falschen Annahme führen, dass Anwendung von sizeof auf einen Zeichentyp den Wert 2 zurückgibt. Diese Probleme werden an anderer Stelle erörtert.