Soweit ich weiß, können Sie dies nicht mit printf tun. Sie könnten natürlich eine Hilfsmethode schreiben, um dies zu erreichen, aber das klingt nicht nach der Richtung, in die Sie gehen möchten.
Ian P
Dafür ist kein Format vordefiniert. Sie müssen es selbst in eine Zeichenfolge umwandeln und dann die Zeichenfolge drucken.
Sie benötigen leider alle zusätzlichen Angebote. Dieser Ansatz BYTE_TO_BINARYbirgt die Effizienzrisiken von Makros (geben Sie keine Funktion als Argument an ), vermeidet jedoch die Speicherprobleme und Mehrfachaufrufe von strcat in einigen anderen Vorschlägen.
Und hat auch den Vorteil, mehrfach aufrufbar zu sein, printfwas diejenigen mit staticPuffern nicht können.
Patrick Schlüter
4
Ich habe mir die Freiheit genommen, um die Änderung %dzu %c, weil es noch schneller sein sollte ( %dhat Ziffern-> char - Konvertierung, während %ceinfach das Argument ausgibt
Beachten Sie, dass dieser Ansatz nicht stapelfreundlich ist. Angenommen, intauf dem System sind 32 Bit vorhanden, erfordert das Drucken eines einzelnen 32-Bit-Werts Platz für 32 * 4-Byte-Werte. insgesamt 128 Bytes. Was je nach Stapelgröße ein Problem sein kann oder nicht.
user694733
1
Es ist wichtig, Klammern um das Byte im Makro einzufügen, da sonst beim Senden einer Operation BYTE_TO_BINARY (a | b) -> a | Probleme auftreten können b & 0x01! = (a | b) & 0x01
Ivan Hoffmann
203
Binär für jeden Datentyp drucken
//assumes little endianvoid printBits(size_tconst size,voidconst*const ptr){unsignedchar*b =(unsignedchar*) ptr;unsignedchar byte;int i, j;for(i=size-1;i>=0;i--){for(j=7;j>=0;j--){
byte =(b[i]>> j)&1;
printf("%u", byte);}}
puts("");}
Prüfung
int main(int argv,char* argc[]){int i =23;uint ui = UINT_MAX;float f =23.45f;
printBits(sizeof(i),&i);
printBits(sizeof(ui),&ui);
printBits(sizeof(f),&f);return0;}
Schlagen Sie size_t i; for (i=size; i-- > 0; )zu vermeiden size_tvs. intmis-match.
chux
1
Könnte jemand bitte die Logik hinter diesem Code näher erläutern?
jII
2
Nehmen Sie jedes Byte in ptr(äußere Schleife); Maskieren Sie dann für jedes Bit das aktuelle Byte (innere Schleife) das Byte durch das aktuelle Bit ( 1 << j). Verschieben Sie dieses Recht nach rechts, was zu einem Byte führt, das 0 ( 0000 0000b) oder 1 ( 0000 0001b) enthält. Drucken Sie das resultierende Byte printf mit Format %u. HTH.
Nielsbot
1
@ ZX9 Beachten Sie, dass der vorgeschlagene Code verwendet >mit size_tund nicht die >=von Ihrem Kommentar zu bestimmen , wann die Schleife zu beenden.
chux
3
@ ZX9 Immer noch ein nützlicher Originalkommentar von Ihnen, da Codierer angesichts der Verwendung von >und >=mit vorzeichenlosen Typen in Randfällen vorsichtig sein müssen . 0ist ein vorzeichenloser Randfall und tritt häufig auf, im Gegensatz zu vorzeichenbehafteter Mathematik mit weniger häufigem INT_MAX/INT_MIN.
chux
151
Hier ist ein kurzer Hack, um Techniken zu demonstrieren, mit denen Sie das tun können, was Sie wollen.
#include<stdio.h>/* printf */#include<string.h>/* strcat */#include<stdlib.h>/* strtol */constchar*byte_to_binary(int x){staticchar b[9];
b[0]='\0';int z;for(z =128; z >0; z >>=1){
strcat(b,((x & z)== z)?"1":"0");}return b;}int main(void){{/* binary string to int */char*tmp;char*b ="0101";
printf("%d\n", strtol(b,&tmp,2));}{/* byte to binary string */
printf("%s\n", byte_to_binary(5));}return0;}
Dies ist sicherlich weniger "seltsam" als das benutzerdefinierte Schreiben einer Escape-Überladung für printf. Es ist auch für einen Entwickler, der neu im Code ist, einfach zu verstehen.
Furious Coder
43
Einige Änderungen: strcatDies ist eine ineffiziente Methode zum Hinzufügen eines einzelnen Zeichens zur Zeichenfolge bei jedem Durchlauf der Schleife. Fügen Sie stattdessen ein hinzu char *p = b;und ersetzen Sie die innere Schleife durch *p++ = (x & z) ? '1' : '0'. zsollte bei 128 (2 ^ 7) statt 256 (2 ^ 8) beginnen. Erwägen Sie eine Aktualisierung, um einen Zeiger auf den zu verwendenden Puffer (zur Thread-Sicherheit) zu verwenden, ähnlich wie inet_ntoa().
Tomlogic
3
@ EvilTeach: Sie verwenden selbst einen ternären Operator als Parameter für strcat()! Ich bin damit einverstanden, dass dies strcatwahrscheinlich einfacher zu verstehen ist als das Nachinkrementieren eines dereferenzierten Zeigers für die Zuweisung, aber selbst Anfänger müssen wissen, wie sie die Standardbibliothek richtig verwenden. Vielleicht wäre die Verwendung eines indizierten Arrays für die Zuweisung eine gute Demonstration gewesen (und funktioniert tatsächlich, da sie bnicht jedes Mal, wenn Sie die Funktion aufrufen, auf Null gesetzt wird).
Tomlogic
3
Zufällig: Das binäre Pufferzeichen ist statisch und wird in der Zuweisung auf alle Nullen gelöscht. Dies löscht es nur beim ersten Ausführen und danach nicht mehr, sondern verwendet stattdessen den letzten Wert.
Markwatson
8
Außerdem sollte dies dokumentieren, dass das vorherige Ergebnis nach erneutem Aufrufen der Funktion ungültig ist, sodass Aufrufer nicht versuchen sollten, es wie folgt zu verwenden : printf("%s + %s = %s", byte_to_binary(3), byte_to_binary(4), byte_to_binary(3+4)).
Paŭlo Ebermann
84
Normalerweise gibt es in glibc keinen binären Konvertierungsspezifizierer.
In glibc können der Funktionsfamilie printf () benutzerdefinierte Konvertierungstypen hinzugefügt werden. Siehe register_printf_function für Details. Sie können eine benutzerdefinierte% b-Konvertierung für Ihren eigenen Gebrauch hinzufügen, wenn dies den Anwendungscode vereinfacht, damit er verfügbar ist.
Hier ist ein Beispiel für die Implementierung eines benutzerdefinierten Druckformats in glibc.
Ich habe immer mein eigenes v [snf] printf () für die begrenzten Fälle geschrieben, in denen ich verschiedene Radixe haben wollte: Ich bin so froh, dass ich darüber gestöbert habe.
Jamie
3
warning: 'register_printf_function' is deprecated [-Wdeprecated-declarations]Es gibt jedoch eine neue Funktion, um dasselbe zu tun : register_printf_specifier(). Ein Beispiel für die neue Nutzung finden Sie hier: codereview.stackexchange.com/q/219994/200418
Cacahuete Frito
47
Sie können einen kleinen Tisch verwenden, um die Geschwindigkeit 1 zu verbessern . Ähnliche Techniken sind in der eingebetteten Welt nützlich, um beispielsweise ein Byte zu invertieren:
1 Ich beziehe mich hauptsächlich auf eingebettete Anwendungen, bei denen Optimierer nicht so aggressiv sind und der Geschwindigkeitsunterschied sichtbar ist.
Drucken Sie das niedrigstwertige Bit und verschieben Sie es nach rechts. Wenn Sie dies tun, bis die Ganzzahl Null wird, wird die Binärdarstellung ohne führende Nullen in umgekehrter Reihenfolge gedruckt. Mit der Rekursion kann die Reihenfolge ganz einfach korrigiert werden.
Für mich ist dies eine der saubersten Lösungen für das Problem. Wenn Sie ein 0bPräfix und ein nachfolgendes neues Zeilenzeichen mögen , empfehle ich, die Funktion einzuschließen.
Fehler: Zu wenige Argumente für Funktionsaufruf, erwartete 2, haben 1 putc ((Nummer & 1)? '1': '0');
Koray Tugay
@KorayTugay Danke, dass du darauf hingewiesen hast. Ich habe den Funktionsaufruf korrigiert und eine Demo hinzugefügt.
Danijar
6
Sie sollten auch eine vorzeichenlose int-Nummer verwenden, da die Funktion bei einer negativen Nummer einen endlosen rekursiven Aufruf ausführt.
Puffy
Effizienterer Ansatz, da in ASCII '0' + 1 = '1':putc('0'+(number&1), stdout);
Roger Dueck
22
Basierend auf @William Whyte Antwort, das ist ein Makro , das bietet int8, 16, 32& 64Versionen, die Wiederverwendung von INT8Makro um Wiederholungen zu vermeiden.
Beachten Sie, dass dieser Code für jede Basis zwischen 2 und 10 genauso gut funktioniert, wenn Sie nur die 2 durch die gewünschte Basis ersetzen. Verwendung ist:
Ja, das kannst du machen. Aber es ist wirklich schlechtes Design. Selbst wenn Sie keine Threads oder Wiedereintritte haben, muss der Aufrufer wissen, dass der statische Puffer wiederverwendet wird und dass solche Dinge char *a = binary_fmt(x), *b = binary_fmt(y);nicht wie erwartet funktionieren. Wenn der Aufrufer gezwungen wird, einen Puffer zu übergeben, wird die Speicheranforderung explizit. Dem Aufrufer steht es natürlich frei, einen statischen Puffer zu verwenden, wenn dies wirklich gewünscht wird, und dann wird die Wiederverwendung desselben Puffers explizit. Beachten Sie auch, dass bei modernen PIC-ABIs statische Puffer normalerweise mehr Code für den Zugriff kosten als Puffer auf dem Stapel.
R .. GitHub STOP HELPING ICE
8
Das ist immer noch ein schlechtes Design. In diesen Fällen ist ein zusätzlicher Kopierschritt erforderlich, und es ist nicht weniger teuer, als wenn der Anrufer den Puffer bereitstellt, selbst wenn kein Kopieren erforderlich wäre. Die Verwendung von statischem Speicher ist nur eine schlechte Redewendung.
R .. GitHub STOP HELPING ICE
3
Sie müssen den Namespace der Präprozessor- oder Variablensymboltabelle mit einem unnötigen zusätzlichen Namen verschmutzen, der verwendet werden muss, um den von jedem Anrufer zugewiesenen Speicher richtig zu dimensionieren , und jeden Anrufer dazu zwingen, diesen Wert zu kennen und die erforderliche Menge von zuzuweisen Speicher ist ein schlechtes Design, wenn die einfachere funktionslokale Speicherlösung für die meisten Absichten und Zwecke ausreicht und wenn ein einfacher Aufruf von strdup () 99% der restlichen Verwendungen abdeckt.
Greg A. Woods
5
Hier müssen wir nicht zustimmen. Ich kann nicht sehen, wie das Hinzufügen eines unauffälligen Präprozessorsymbols der Schädlichkeit nahe kommt, die Anwendungsfälle stark einzuschränken, die Schnittstelle fehleranfällig zu machen, permanenten Speicher für die Dauer des Programms für einen temporären Wert zu reservieren und bei den meisten schlechteren Code zu generieren moderne Plattformen.
R .. GitHub STOP HELPING ICE
5
Ich befürworte keine Mikrooptimierung ohne Grund (dh Messungen). Ich denke jedoch, dass Leistung, auch wenn sie auf der Mikrogewinnskala liegt, erwähnenswert ist, wenn sie als Bonus zusammen mit einem grundlegend überlegenen Design angeboten wird.
Klarer, wenn Sie '1'und '0'anstelle von 49und 48in Ihrem ternären verwenden. Sollte außerdem b9 Zeichen lang sein, damit das letzte Zeichen ein Nullterminator bleiben kann.
Tomlogic
Auch B muss jedes Mal initialisiert werden.
EvilTeach
2
Nicht, wenn Sie einige ändern: 1. Platz für eine endgültige Null hinzufügen: static char b[9] = {0}2. Deklaration aus der Schleife verschieben: int z,y;3. Endgültige Null hinzufügen : b[y] = 0. Auf diese Weise ist keine Reinitalisierung erforderlich.
Kobor42
1
Schöne Lösung. Ich würde allerdings ein paar Sachen ändern. Dh in der Zeichenfolge rückwärts gehen, damit Eingaben beliebiger Größe ordnungsgemäß verarbeitet werden können.
Kobor42
Alle diese 8s sollten durch ersetzt werden CHAR_BIT.
Funktioniert für alle Größen und für signierte und nicht signierte Ints. Das '& 1' wird benötigt, um vorzeichenbehaftete Ints zu verarbeiten, da die Verschiebung möglicherweise eine Vorzeichenerweiterung bewirkt.
Es gibt so viele Möglichkeiten, dies zu tun. Hier ist eine supereinfache Methode zum Drucken von 32 Bit oder n Bits von einem vorzeichenbehafteten oder vorzeichenlosen 32-Bit-Typ (kein Negativ setzen, wenn signiert, nur Drucken der tatsächlichen Bits) und ohne Wagenrücklauf. Beachten Sie, dass i vor der Bitverschiebung dekrementiert wird:
Was ist mit der Rückgabe einer Zeichenfolge mit den Bits, die später gespeichert oder gedruckt werden sollen? Sie können den Speicher entweder zuweisen und zurückgeben, und der Benutzer muss ihn freigeben, oder Sie geben eine statische Zeichenfolge zurück, die jedoch beim erneuten Aufruf oder durch einen anderen Thread überlastet wird. Beide Methoden gezeigt:
// memory allocated string returned which needs to be freedchar*pstr = int_to_bitstring_alloc(0x97e50ae6,17);
printf("bits = 0b%s\n", pstr);
free(pstr);// no free needed but you need to copy the string to save it somewhere elsechar*pstr2 = int_to_bitstring_static(0x97e50ae6,17);
printf("bits = 0b%s\n", pstr2);
Keine der zuvor veröffentlichten Antworten ist genau das, wonach ich gesucht habe, also habe ich eine geschrieben. Es ist super einfach,% B mit dem zu verwenden printf!
/*
* File: main.c
* Author: Techplex.Engineer
*
* Created on February 14, 2012, 9:16 PM
*/#include<stdio.h>#include<stdlib.h>#include<printf.h>#include<math.h>#include<string.h>staticint printf_arginfo_M(conststruct printf_info *info,size_t n,int*argtypes){/* "%M" always takes one argument, a pointer to uint8_t[6]. */if(n >0){
argtypes[0]= PA_POINTER;}return1;}/* printf_arginfo_M */staticint printf_output_M(FILE*stream,conststruct printf_info *info,constvoid*const*args){int value =0;int len;
value =*(int**)(args[0]);//Beginning of my code ------------------------------------------------------------char buffer [50]="";//Is this bad?char buffer2 [50]="";//Is this bad?int bits = info->width;if(bits <=0)
bits =8;// Default to 8 bitsint mask = pow(2, bits -1);while(mask >0){
sprintf(buffer,"%s",(((value & mask)>0)?"1":"0"));
strcat(buffer2, buffer);
mask >>=1;}
strcat(buffer2,"\n");// End of my code --------------------------------------------------------------
len = fprintf(stream,"%s", buffer2);return len;}/* printf_output_M */int main(int argc,char** argv){
register_printf_specifier('B', printf_output_M, printf_arginfo_M);
printf("%4B\n",65);return(EXIT_SUCCESS);}
Guter Anruf, ja, das wird es ... Mir wurde gesagt, ich müsse Malloc verwenden, jemals das anziehen?
TechplexEngineer
ja natürlich. super einfach:char* buffer = (char*) malloc(sizeof(char) * 50);
Janus Troelsen
@ JanusTroelsen oder viel sauberer, kleiner, wartbar:char *buffer = malloc(sizeof(*buffer) * 50);
Shahbaz
Warum sollte sich "% B" in dieser Hinsicht von "% b" unterscheiden? Frühere Antworten besagten Dinge wie "Es gibt keine Formatierungsfunktion in der C-Standardbibliothek, um solche Binärdateien auszugeben." und " Einige Laufzeiten unterstützen"% b ", obwohl dies kein Standard ist." .
Peter Mortensen
8
Einige Laufzeiten unterstützen "% b", obwohl dies kein Standard ist.
Dies ist eigentlich eine Eigenschaft der C-Laufzeitbibliothek, nicht des Compilers.
cjm
7
Dieser Code sollte Ihre Anforderungen bis zu 64 Bit erfüllen. Ich habe 2 Funktionen pBin & pBinFill erstellt. Beide machen dasselbe, aber pBinFill füllt die führenden Felder mit fillChar aus. Die Testfunktion generiert einige Testdaten und druckt sie dann mit der Funktion aus.
char* pBinFill(longint x,char*so,char fillChar);// version with fillchar* pBin(longint x,char*so);// version without fill#define kDisplayWidth 64char* pBin(longint x,char*so){char s[kDisplayWidth+1];int i=kDisplayWidth;
s[i--]=0x00;// terminate stringdo{// fill in array from right to left
s[i--]=(x &1)?'1':'0';// determine bit
x>>=1;// shift right 1 bit}while( x >0);
i++;// point to last valid character
sprintf(so,"%s",s+i);// stick it in the temp string stringreturn so;}
char* pBinFill(longint x,char*so,char fillChar){// fill in array from right to leftchar s[kDisplayWidth+1];int i=kDisplayWidth;
s[i--]=0x00;// terminate stringdo{// fill in array from right to left
s[i--]=(x &1)?'1':'0';
x>>=1;// shift right 1 bit}while( x >0);while(i>=0) s[i--]=fillChar;// fill with fillChar
sprintf(so,"%s",s);return so;}
void test(){char so[kDisplayWidth+1];// working buffer for pBinlongint val=1;do{
printf("%ld =\t\t%#lx =\t\t0b%s\n",val,val,pBinFill(val,so,'0'));
val*=11;// generate test data}while(val <100000000);}Output:00000001=0x000001=0b0000000000000000000000000000000100000011=0x00000b=0b0000000000000000000000000000101100000121=0x000079=0b0000000000000000000000000111100100001331=0x000533=0b0000000000000000000001010011001100014641=0x003931=0b0000000000000000001110010011000100161051=0x02751b=0b0000000000000010011101010001101101771561=0x1b0829=0b0000000000011011000010000010100119487171=0x12959c3=0b00000001001010010101100111000011
"#define width 64" steht in Konflikt mit stream.h von log4cxx. Bitte verwenden Sie konventionell zufällig definierte Namen :)
Kagali-San
5
@mhambra: Sie sollten log4cxx für die Verwendung eines generischen Namens wie widthstattdessen ausschalten !
u0b34a0f6ae
7
Gibt es einen printf-Konverter zum Drucken im Binärformat?
Die printf()Familie kann nur in Basis 8, 10 und 16 direkt mit den Standardspezifizierern drucken. Ich schlage vor, eine Funktion zu erstellen, die die Zahl gemäß den besonderen Anforderungen des Codes in eine Zeichenfolge konvertiert.
Zum Drucken in einer beliebigen Basis [2-36]
Alle anderen Antworten haben bisher mindestens eine dieser Einschränkungen.
Verwenden Sie den statischen Speicher für den Rückgabepuffer. Dies begrenzt die Häufigkeit, mit der die Funktion als Argument verwendet werden kann printf().
Ordnen Sie Speicher, für den der aufrufende Code erforderlich ist, freien Zeigern zu.
Der aufrufende Code muss explizit einen geeigneten Puffer bereitstellen.
Rufen Sie printf()direkt an. Dies verpflichtet eine neue Funktion zu fprintf(), sprintf(), vsprintf()etc.
Verwenden Sie einen reduzierten ganzzahligen Bereich.
Das Folgende hat keine der oben genannten Einschränkungen . Es erfordert C99 oder höher und die Verwendung von "%s". Es verwendet ein zusammengesetztes Literal , um den Pufferraum bereitzustellen. Es hat keine Probleme mit mehreren Anrufen in einem printf().
#include<assert.h>#include<limits.h>#define TO_BASE_N (sizeof(unsigned)*CHAR_BIT +1)// v. compound literal .v#define TO_BASE(x, b) my_to_base((char[TO_BASE_N]){""},(x),(b))// Tailor the details of the conversion function as needed// This one does not display unneeded leading zeros// Use return value, not `buf`char*my_to_base(char*buf,unsigned i,int base){
assert(base >=2&& base <=36);char*s =&buf[TO_BASE_N -1];*s ='\0';do{
s--;*s ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % base];
i /= base;}while(i);// Could employ memmove here to move the used buffer to the beginningreturn s;}#include<stdio.h>int main(void){int ip1 =0x01020304;int ip2 =0x05060708;
printf("%s %s\n", TO_BASE(ip1,16), TO_BASE(ip2,16));
printf("%s %s\n", TO_BASE(ip1,2), TO_BASE(ip2,2));
puts(TO_BASE(ip1,8));
puts(TO_BASE(ip1,36));return0;}
Das ist sehr nützlich. Wissen Sie, wie man es in C ++ benutzt? Beim Kompilieren wird der Fehler "Schweregrad Code Beschreibung Projektdatei Zeilenunterdrückungsstatus Fehler C4576" generiert. Ein in Klammern stehender Typ gefolgt von einer Initialisiererliste ist eine nicht standardmäßige explizite Typkonvertierungssyntax. Hallo C: \ my_projects \ hello \ hello \ main.cpp 39 "
Nur ein Lernender
1
@Justalearner Dies generiert ein C ++, da bei Verwendung eines zusammengesetzten C-Feature- Literals, das nicht Teil von C ++ ist. Veröffentlichen Sie möglicherweise Ihre C ++ - Implementierung, die versucht, dasselbe zu tun - auch wenn sie unvollständig ist, ich bin sicher, dass Sie Hilfe erhalten werden -, solange Sie zuerst Ihren Versuch zeigen.
chux
6
Vielleicht ein bisschen OT, aber wenn Sie dies nur zum Debuggen benötigen, um einige von Ihnen ausgeführte Binäroperationen zu verstehen oder nachzuvollziehen, können Sie sich wcalc (einen einfachen Konsolenrechner) ansehen. Mit den Optionen -b erhalten Sie eine binäre Ausgabe.
es gibt zu wenig andere Optionen an dieser Front, ... ruby -e 'printf("%b\n", 0xabc)', dcgefolgt von 2ogefolgt von 0x123p, und so weiter.
Lindes
6
In der C-Standardbibliothek gibt es keine Formatierungsfunktion, um solche Binärdateien auszugeben. Alle Formatierungsvorgänge, die von der printf-Familie unterstützt werden, beziehen sich auf lesbaren Text.
Wenn Sie dynamischen Speicher (durch std::string) verwenden möchten , können Sie das staticArray auch entfernen. Am einfachsten wäre es, einfach das staticQualifikationsmerkmal zu löschen und bdie Funktion lokal zu machen .
Shahbaz
((x>>z) & 0x01) + '0'ist ausreichend.
Jason C
4
Drucken Sie Bits von jedem Typ mit weniger Code und Ressourcen
Dieser Ansatz hat als Attribute:
Arbeitet mit Variablen und Literalen.
Iteriert nicht alle Bits, wenn dies nicht erforderlich ist.
Rufen Sie printf nur auf, wenn ein Byte vollständig ist (nicht unnötig für alle Bits).
Funktioniert für jeden Typ.
Funktioniert mit kleinen und großen Endianness (verwendet GCC #defines zur Überprüfung).
Verwendet typeof (), das nicht dem C-Standard entspricht, aber weitgehend definiert ist.
Ich habe einen anderen Ansatz ( bitprint.h ) verwendet, um eine Tabelle mit allen Bytes (als Bitfolgen) zu füllen und sie basierend auf dem Eingabe- / Indexbyte zu drucken. Ein Blick lohnt sich.
void
print_binary(unsignedint n){unsignedint mask =0;/* this grotesque hack creates a bit pattern 1000... *//* regardless of the size of an unsigned int */
mask =~mask ^(~mask >>1);for(; mask !=0; mask >>=1){
putchar((n & mask)?'1':'0');}}
Oder addiere 0 oder 1 zum Zeichenwert von '0';) Kein Ternär erforderlich.
Eule
3
Ich mochte den Code von paniq, der statische Puffer ist eine gute Idee. Es schlägt jedoch fehl, wenn Sie mehrere Binärformate in einem einzigen printf () möchten, da immer derselbe Zeiger zurückgegeben und das Array überschrieben wird.
Hier ist ein Drop-In im C-Stil, das den Zeiger auf einen geteilten Puffer dreht.
char*
format_binary(unsignedint x){#define MAXLEN 8// width of output format#define MAXCNT 4// count per printf statementstaticchar fmtbuf[(MAXLEN+1)*MAXCNT];staticint count =0;char*b;
count = count % MAXCNT +1;
b =&fmtbuf[(MAXLEN+1)*count];
b[MAXLEN]='\0';for(int z =0; z < MAXLEN; z++){ b[MAXLEN-1-z]=((x>>z)&0x1)?'1':'0';}return b;}
Sobald counterreicht MAXCNT - 1, würde das nächste Inkrement von countes MAXCNTanstelle von Null machen, was einen Zugriff außerhalb der Grenzen des Arrays verursachen würde. Du hättest es tun sollen count = (count + 1) % MAXCNT.
Shahbaz
1
Übrigens würde dies später einen Entwickler überraschen, der MAXCNT + 1Aufrufe dieser Funktion in einem einzigen verwendet printf. Wenn Sie die Option für mehr als eine Sache angeben möchten, machen Sie sie im Allgemeinen unendlich. Zahlen wie 4 können nur Probleme verursachen.
Shahbaz
3
Kein Standard und tragbarer Weg.
Einige Implementierungen bieten itoa () , aber es wird nicht in den meisten sein, und es hat eine etwas miese Schnittstelle. Der Code befindet sich jedoch hinter dem Link und sollte es Ihnen ermöglichen, Ihren eigenen Formatierer ziemlich einfach zu implementieren.
Basierend auf @ ideasman42 Vorschlag in seiner Antwort, das ist ein Makro , das bietet int8, 16, 32& 64Versionen, die Wiederverwendung den INT8Makro um Wiederholungen zu vermeiden.
Zur besseren Lesbarkeit können Sie Folgendes ändern: #define PRINTF_BINARY_SEPARATORzu #define PRINTF_BINARY_SEPARATOR ","oder#define PRINTF_BINARY_SEPARATOR " "
/* Convert an int to it's binary representation */char*int2bin(int num,int pad){char*str = malloc(sizeof(char)*(pad+1));if(str){
str[pad]='\0';while(--pad>=0){
str[pad]= num &1?'1':'0';
num >>=1;}}else{return"";}return str;}/* example usage */
printf("The number 5 in binary is %s", int2bin(5,4));/* "The number 5 in binary is 0101" */
Das Bezahlen der Kosten für eine Mallocation beeinträchtigt die Leistung. Es ist unfreundlich, die Verantwortung für die Zerstörung des Puffers an den Anrufer weiterzugeben.
EvilTeach
2
Als nächstes wird Ihnen das Speicherlayout angezeigt:
Antworten:
Hacky aber funktioniert bei mir:
Für Multi-Byte-Typen
Sie benötigen leider alle zusätzlichen Angebote. Dieser Ansatz
BYTE_TO_BINARY
birgt die Effizienzrisiken von Makros (geben Sie keine Funktion als Argument an ), vermeidet jedoch die Speicherprobleme und Mehrfachaufrufe von strcat in einigen anderen Vorschlägen.quelle
printf
was diejenigen mitstatic
Puffern nicht können.%d
zu%c
, weil es noch schneller sein sollte (%d
hat Ziffern-> char - Konvertierung, während%c
einfach das Argument ausgibtint
auf dem System sind 32 Bit vorhanden, erfordert das Drucken eines einzelnen 32-Bit-Werts Platz für 32 * 4-Byte-Werte. insgesamt 128 Bytes. Was je nach Stapelgröße ein Problem sein kann oder nicht.Binär für jeden Datentyp drucken
Prüfung
quelle
size_t i; for (i=size; i-- > 0; )
zu vermeidensize_t
vs.int
mis-match.ptr
(äußere Schleife); Maskieren Sie dann für jedes Bit das aktuelle Byte (innere Schleife) das Byte durch das aktuelle Bit (1 << j
). Verschieben Sie dieses Recht nach rechts, was zu einem Byte führt, das 0 (0000 0000b
) oder 1 (0000 0001b
) enthält. Drucken Sie das resultierende Byte printf mit Format%u
. HTH.>
mitsize_t
und nicht die>=
von Ihrem Kommentar zu bestimmen , wann die Schleife zu beenden.>
und>=
mit vorzeichenlosen Typen in Randfällen vorsichtig sein müssen .0
ist ein vorzeichenloser Randfall und tritt häufig auf, im Gegensatz zu vorzeichenbehafteter Mathematik mit weniger häufigemINT_MAX/INT_MIN
.Hier ist ein kurzer Hack, um Techniken zu demonstrieren, mit denen Sie das tun können, was Sie wollen.
quelle
strcat
Dies ist eine ineffiziente Methode zum Hinzufügen eines einzelnen Zeichens zur Zeichenfolge bei jedem Durchlauf der Schleife. Fügen Sie stattdessen ein hinzuchar *p = b;
und ersetzen Sie die innere Schleife durch*p++ = (x & z) ? '1' : '0'
.z
sollte bei 128 (2 ^ 7) statt 256 (2 ^ 8) beginnen. Erwägen Sie eine Aktualisierung, um einen Zeiger auf den zu verwendenden Puffer (zur Thread-Sicherheit) zu verwenden, ähnlich wieinet_ntoa()
.strcat()
! Ich bin damit einverstanden, dass diesstrcat
wahrscheinlich einfacher zu verstehen ist als das Nachinkrementieren eines dereferenzierten Zeigers für die Zuweisung, aber selbst Anfänger müssen wissen, wie sie die Standardbibliothek richtig verwenden. Vielleicht wäre die Verwendung eines indizierten Arrays für die Zuweisung eine gute Demonstration gewesen (und funktioniert tatsächlich, da sieb
nicht jedes Mal, wenn Sie die Funktion aufrufen, auf Null gesetzt wird).printf("%s + %s = %s", byte_to_binary(3), byte_to_binary(4), byte_to_binary(3+4))
.Normalerweise gibt es in glibc keinen binären Konvertierungsspezifizierer.
In glibc können der Funktionsfamilie printf () benutzerdefinierte Konvertierungstypen hinzugefügt werden. Siehe register_printf_function für Details. Sie können eine benutzerdefinierte% b-Konvertierung für Ihren eigenen Gebrauch hinzufügen, wenn dies den Anwendungscode vereinfacht, damit er verfügbar ist.
Hier ist ein Beispiel für die Implementierung eines benutzerdefinierten Druckformats in glibc.
quelle
warning: 'register_printf_function' is deprecated [-Wdeprecated-declarations]
Es gibt jedoch eine neue Funktion, um dasselbe zu tun :register_printf_specifier()
. Ein Beispiel für die neue Nutzung finden Sie hier: codereview.stackexchange.com/q/219994/200418Sie können einen kleinen Tisch verwenden, um die Geschwindigkeit 1 zu verbessern . Ähnliche Techniken sind in der eingebetteten Welt nützlich, um beispielsweise ein Byte zu invertieren:
1 Ich beziehe mich hauptsächlich auf eingebettete Anwendungen, bei denen Optimierer nicht so aggressiv sind und der Geschwindigkeitsunterschied sichtbar ist.
quelle
Drucken Sie das niedrigstwertige Bit und verschieben Sie es nach rechts. Wenn Sie dies tun, bis die Ganzzahl Null wird, wird die Binärdarstellung ohne führende Nullen in umgekehrter Reihenfolge gedruckt. Mit der Rekursion kann die Reihenfolge ganz einfach korrigiert werden.
Für mich ist dies eine der saubersten Lösungen für das Problem. Wenn Sie ein
0b
Präfix und ein nachfolgendes neues Zeilenzeichen mögen , empfehle ich, die Funktion einzuschließen.Online-Demo
quelle
putc('0'+(number&1), stdout);
Basierend auf @William Whyte Antwort, das ist ein Makro , das bietet
int8
,16
,32
&64
Versionen, die Wiederverwendung vonINT8
Makro um Wiederholungen zu vermeiden.Dies gibt aus:
Zur besseren Lesbarkeit möchten Sie möglicherweise ein Trennzeichen hinzufügen, z.
quelle
PRINTF_BYTE_TO_BINARY_INT#
Definitionen hinzu, die optional verwendet werden soll.Hier ist eine Version der Funktion, die nicht unter Wiedereintrittsproblemen oder Einschränkungen der Größe / des Typs des Arguments leidet:
Beachten Sie, dass dieser Code für jede Basis zwischen 2 und 10 genauso gut funktioniert, wenn Sie nur die 2 durch die gewünschte Basis ersetzen. Verwendung ist:
Wo
x
ist ein integraler Ausdruck?quelle
char *a = binary_fmt(x), *b = binary_fmt(y);
nicht wie erwartet funktionieren. Wenn der Aufrufer gezwungen wird, einen Puffer zu übergeben, wird die Speicheranforderung explizit. Dem Aufrufer steht es natürlich frei, einen statischen Puffer zu verwenden, wenn dies wirklich gewünscht wird, und dann wird die Wiederverwendung desselben Puffers explizit. Beachten Sie auch, dass bei modernen PIC-ABIs statische Puffer normalerweise mehr Code für den Zugriff kosten als Puffer auf dem Stapel.quelle
'1'
und'0'
anstelle von49
und48
in Ihrem ternären verwenden. Sollte außerdemb
9 Zeichen lang sein, damit das letzte Zeichen ein Nullterminator bleiben kann.static char b[9] = {0}
2. Deklaration aus der Schleife verschieben:int z,y;
3. Endgültige Null hinzufügen :b[y] = 0
. Auf diese Weise ist keine Reinitalisierung erforderlich.8
s sollten durch ersetzt werdenCHAR_BIT
.Schnelle und einfache Lösung:
Funktioniert für alle Größen und für signierte und nicht signierte Ints. Das '& 1' wird benötigt, um vorzeichenbehaftete Ints zu verarbeiten, da die Verschiebung möglicherweise eine Vorzeichenerweiterung bewirkt.
Es gibt so viele Möglichkeiten, dies zu tun. Hier ist eine supereinfache Methode zum Drucken von 32 Bit oder n Bits von einem vorzeichenbehafteten oder vorzeichenlosen 32-Bit-Typ (kein Negativ setzen, wenn signiert, nur Drucken der tatsächlichen Bits) und ohne Wagenrücklauf. Beachten Sie, dass i vor der Bitverschiebung dekrementiert wird:
Was ist mit der Rückgabe einer Zeichenfolge mit den Bits, die später gespeichert oder gedruckt werden sollen? Sie können den Speicher entweder zuweisen und zurückgeben, und der Benutzer muss ihn freigeben, oder Sie geben eine statische Zeichenfolge zurück, die jedoch beim erneuten Aufruf oder durch einen anderen Thread überlastet wird. Beide Methoden gezeigt:
Rufen Sie an mit:
quelle
Keine der zuvor veröffentlichten Antworten ist genau das, wonach ich gesucht habe, also habe ich eine geschrieben. Es ist super einfach,% B mit dem zu verwenden
printf
!quelle
char* buffer = (char*) malloc(sizeof(char) * 50);
char *buffer = malloc(sizeof(*buffer) * 50);
Einige Laufzeiten unterstützen "% b", obwohl dies kein Standard ist.
Siehe auch hier für eine interessante Diskussion:
http://bytes.com/forum/thread591027.html
HTH
quelle
Dieser Code sollte Ihre Anforderungen bis zu 64 Bit erfüllen. Ich habe 2 Funktionen pBin & pBinFill erstellt. Beide machen dasselbe, aber pBinFill füllt die führenden Felder mit fillChar aus. Die Testfunktion generiert einige Testdaten und druckt sie dann mit der Funktion aus.
quelle
width
stattdessen ausschalten !Die
printf()
Familie kann nur in Basis 8, 10 und 16 direkt mit den Standardspezifizierern drucken. Ich schlage vor, eine Funktion zu erstellen, die die Zahl gemäß den besonderen Anforderungen des Codes in eine Zeichenfolge konvertiert.Zum Drucken in einer beliebigen Basis [2-36]
Alle anderen Antworten haben bisher mindestens eine dieser Einschränkungen.
Verwenden Sie den statischen Speicher für den Rückgabepuffer. Dies begrenzt die Häufigkeit, mit der die Funktion als Argument verwendet werden kann
printf()
.Ordnen Sie Speicher, für den der aufrufende Code erforderlich ist, freien Zeigern zu.
Der aufrufende Code muss explizit einen geeigneten Puffer bereitstellen.
Rufen Sie
printf()
direkt an. Dies verpflichtet eine neue Funktion zufprintf()
,sprintf()
,vsprintf()
etc.Verwenden Sie einen reduzierten ganzzahligen Bereich.
Das Folgende hat keine der oben genannten Einschränkungen . Es erfordert C99 oder höher und die Verwendung von
"%s"
. Es verwendet ein zusammengesetztes Literal , um den Pufferraum bereitzustellen. Es hat keine Probleme mit mehreren Anrufen in einemprintf()
.Ausgabe
quelle
Vielleicht ein bisschen OT, aber wenn Sie dies nur zum Debuggen benötigen, um einige von Ihnen ausgeführte Binäroperationen zu verstehen oder nachzuvollziehen, können Sie sich wcalc (einen einfachen Konsolenrechner) ansehen. Mit den Optionen -b erhalten Sie eine binäre Ausgabe.
z.B
quelle
ruby -e 'printf("%b\n", 0xabc)'
,dc
gefolgt von2o
gefolgt von0x123p
, und so weiter.In der C-Standardbibliothek gibt es keine Formatierungsfunktion, um solche Binärdateien auszugeben. Alle Formatierungsvorgänge, die von der printf-Familie unterstützt werden, beziehen sich auf lesbaren Text.
quelle
Die folgende rekursive Funktion kann nützlich sein:
quelle
Ich habe die Top-Lösung für Größe und C ++ optimiert und bin zu dieser Lösung gekommen:
quelle
std::string
) verwenden möchten , können Sie dasstatic
Array auch entfernen. Am einfachsten wäre es, einfach dasstatic
Qualifikationsmerkmal zu löschen undb
die Funktion lokal zu machen .((x>>z) & 0x01) + '0'
ist ausreichend.Drucken Sie Bits von jedem Typ mit weniger Code und Ressourcen
Dieser Ansatz hat als Attribute:
Ausgabe
Ich habe einen anderen Ansatz ( bitprint.h ) verwendet, um eine Tabelle mit allen Bytes (als Bitfolgen) zu füllen und sie basierend auf dem Eingabe- / Indexbyte zu drucken. Ein Blick lohnt sich.
quelle
quelle
Ich mochte den Code von paniq, der statische Puffer ist eine gute Idee. Es schlägt jedoch fehl, wenn Sie mehrere Binärformate in einem einzigen printf () möchten, da immer derselbe Zeiger zurückgegeben und das Array überschrieben wird.
Hier ist ein Drop-In im C-Stil, das den Zeiger auf einen geteilten Puffer dreht.
quelle
count
erreichtMAXCNT - 1
, würde das nächste Inkrement voncount
esMAXCNT
anstelle von Null machen, was einen Zugriff außerhalb der Grenzen des Arrays verursachen würde. Du hättest es tun sollencount = (count + 1) % MAXCNT
.MAXCNT + 1
Aufrufe dieser Funktion in einem einzigen verwendetprintf
. Wenn Sie die Option für mehr als eine Sache angeben möchten, machen Sie sie im Allgemeinen unendlich. Zahlen wie 4 können nur Probleme verursachen.Kein Standard und tragbarer Weg.
Einige Implementierungen bieten itoa () , aber es wird nicht in den meisten sein, und es hat eine etwas miese Schnittstelle. Der Code befindet sich jedoch hinter dem Link und sollte es Ihnen ermöglichen, Ihren eigenen Formatierer ziemlich einfach zu implementieren.
quelle
Eine generische Konvertierung eines beliebigen Integraltyps in die binäre Zeichenfolgendarstellung unter Verwendung der Standardbibliothek :
Oder nur:
std::cout << std::bitset<sizeof(num) * 8>(num);
quelle
Meine Lösung:
quelle
Basierend auf @ ideasman42 Vorschlag in seiner Antwort, das ist ein Makro , das bietet
int8
,16
,32
&64
Versionen, die Wiederverwendung denINT8
Makro um Wiederholungen zu vermeiden.Dies gibt aus:
Zur besseren Lesbarkeit können Sie Folgendes ändern:
#define PRINTF_BINARY_SEPARATOR
zu#define PRINTF_BINARY_SEPARATOR ","
oder#define PRINTF_BINARY_SEPARATOR " "
Dies wird Folgendes ausgeben:
oder
quelle
Verwenden:
Weitere Informationen finden Sie unter Drucken von Binärzahlen über printf .
quelle
sollte funktionieren - ungetestet.
quelle
quelle
Als nächstes wird Ihnen das Speicherlayout angezeigt:
quelle
Hier ist eine kleine Variation der paniq -Lösung, die Vorlagen verwendet, um das Drucken von 32- und 64-Bit-Ganzzahlen zu ermöglichen:
Und kann verwendet werden wie:
Hier ist das Ergebnis:
quelle