Ich kann mit printf als Hex- oder Oktalzahl drucken. Gibt es ein Format-Tag, das als binäre oder beliebige Basis gedruckt werden soll?
Ich laufe gcc.
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
Ich kann mit printf als Hex- oder Oktalzahl drucken. Gibt es ein Format-Tag, das als binäre oder beliebige Basis gedruckt werden soll?
Ich laufe gcc.
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
Antworten:
Hacky aber funktioniert bei mir:
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
(byte & 0x80 ? '1' : '0'), \
(byte & 0x40 ? '1' : '0'), \
(byte & 0x20 ? '1' : '0'), \
(byte & 0x10 ? '1' : '0'), \
(byte & 0x08 ? '1' : '0'), \
(byte & 0x04 ? '1' : '0'), \
(byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0')
printf("Leading text "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(byte));
Für Multi-Byte-Typen
printf("m: "BYTE_TO_BINARY_PATTERN" "BYTE_TO_BINARY_PATTERN"\n",
BYTE_TO_BINARY(m>>8), BYTE_TO_BINARY(m));
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.
printf
was diejenigen mit static
Puffern nicht können.
%d
zu %c
, weil es noch schneller sein sollte ( %d
hat Ziffern-> char - Konvertierung, während %c
einfach das Argument ausgibt
int
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
//assumes little endian
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char 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);
return 0;
}
size_t i; for (i=size; i-- > 0; )
zu vermeiden size_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.
>
mit size_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äufigem INT_MAX/INT_MIN
.
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 */
const char *byte_to_binary
(
int x
)
{
static char 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));
}
return 0;
}
strcat
Dies 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'
. 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 wie inet_ntoa()
.
strcat()
! Ich bin damit einverstanden, dass dies strcat
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 sie b
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.
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
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:
const char *bit_rep[16] = {
[ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011",
[ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111",
[ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011",
[12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111",
};
void print_byte(uint8_t byte)
{
printf("%s%s", bit_rep[byte >> 4], bit_rep[byte & 0x0F]);
}
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.
#include <stdio.h>
void print_binary(int number)
{
if (number) {
print_binary(number >> 1);
putc((number & 1) ? '1' : '0', stdout);
}
}
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.
putc('0'+(number&1), stdout);
Basierend auf @William Whyte Antwort, das ist ein Makro , das bietet int8
, 16
, 32
& 64
Versionen, die Wiederverwendung von INT8
Makro um Wiederholungen zu vermeiden.
/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i) \
(((i) & 0x80ll) ? '1' : '0'), \
(((i) & 0x40ll) ? '1' : '0'), \
(((i) & 0x20ll) ? '1' : '0'), \
(((i) & 0x10ll) ? '1' : '0'), \
(((i) & 0x08ll) ? '1' : '0'), \
(((i) & 0x04ll) ? '1' : '0'), \
(((i) & 0x02ll) ? '1' : '0'), \
(((i) & 0x01ll) ? '1' : '0')
#define PRINTF_BINARY_PATTERN_INT16 \
PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
PRINTF_BINARY_PATTERN_INT16 PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64 \
PRINTF_BINARY_PATTERN_INT32 PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */
#include <stdio.h>
int main() {
long long int flag = 1648646756487983144ll;
printf("My Flag "
PRINTF_BINARY_PATTERN_INT64 "\n",
PRINTF_BYTE_TO_BINARY_INT64(flag));
return 0;
}
Dies gibt aus:
My Flag 0001011011100001001010110111110101111000100100001111000000101000
Zur besseren Lesbarkeit möchten Sie möglicherweise ein Trennzeichen hinzufügen, z.
My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
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:
#define FMT_BUF_SIZE (CHAR_BIT*sizeof(uintmax_t)+1)
char *binary_fmt(uintmax_t x, char buf[static FMT_BUF_SIZE])
{
char *s = buf + FMT_BUF_SIZE;
*--s = 0;
if (!x) *--s = '0';
for(; x; x/=2) *--s = '0' + x%2;
return s;
}
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:
char tmp[FMT_BUF_SIZE];
printf("%s\n", binary_fmt(x, tmp));
Wo x
ist ein integraler Ausdruck?
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.
const char* byte_to_binary( int x )
{
static char b[sizeof(int)*8+1] = {0};
int y;
long long z;
for (z=1LL<<sizeof(int)*8-1,y=0; z>0; z>>=1,y++)
{
b[y] = ( ((x & z) == z) ? '1' : '0');
}
b[y] = 0;
return b;
}
'1'
und '0'
anstelle von 49
und 48
in Ihrem ternären verwenden. Sollte außerdem b
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 werden CHAR_BIT
.
Schnelle und einfache Lösung:
void printbits(my_integer_type x)
{
for(int i=sizeof(x)<<3; i; i--)
putchar('0'+((x>>(i-1))&1));
}
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:
#define printbits_n(x,n) for (int i=n;i;i--,putchar('0'|(x>>i)&1))
#define printbits_32(x) printbits_n(x,32)
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:
char *int_to_bitstring_alloc(int x, int count)
{
count = count<1 ? sizeof(x)*8 : count;
char *pstr = malloc(count+1);
for(int i = 0; i<count; i++)
pstr[i] = '0' | ((x>>(count-1-i))&1);
pstr[count]=0;
return pstr;
}
#define BITSIZEOF(x) (sizeof(x)*8)
char *int_to_bitstring_static(int x, int count)
{
static char bitbuf[BITSIZEOF(x)+1];
count = (count<1 || count>BITSIZEOF(x)) ? BITSIZEOF(x) : count;
for(int i = 0; i<count; i++)
bitbuf[i] = '0' | ((x>>(count-1-i))&1);
bitbuf[count]=0;
return bitbuf;
}
Rufen Sie an mit:
// memory allocated string returned which needs to be freed
char *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 else
char *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>
static int printf_arginfo_M(const struct 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;
}
return 1;
} /* printf_arginfo_M */
static int printf_output_M(FILE *stream, const struct printf_info *info, const void *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 bits
int 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);
}
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
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(long int x,char *so, char fillChar); // version with fill
char* pBin(long int x, char *so); // version without fill
#define kDisplayWidth 64
char* pBin(long int x,char *so)
{
char s[kDisplayWidth+1];
int i=kDisplayWidth;
s[i--]=0x00; // terminate string
do
{ // 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 string
return so;
}
char* pBinFill(long int x,char *so, char fillChar)
{ // fill in array from right to left
char s[kDisplayWidth+1];
int i=kDisplayWidth;
s[i--]=0x00; // terminate string
do
{ // 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 pBin
long int 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 = 0b00000000000000000000000000000001
00000011 = 0x00000b = 0b00000000000000000000000000001011
00000121 = 0x000079 = 0b00000000000000000000000001111001
00001331 = 0x000533 = 0b00000000000000000000010100110011
00014641 = 0x003931 = 0b00000000000000000011100100110001
00161051 = 0x02751b = 0b00000000000000100111010100011011
01771561 = 0x1b0829 = 0b00000000000110110000100000101001
19487171 = 0x12959c3 = 0b00000001001010010101100111000011
width
stattdessen ausschalten !
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 beginning
return 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));
return 0;
}
Ausgabe
1020304 5060708
1000000100000001100000100 101000001100000011100001000
100401404
A2F44
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
$ wcalc -b "(256 | 3) & 0xff" = 0b11
ruby -e 'printf("%b\n", 0xabc)'
, dc
gefolgt von 2o
gefolgt von 0x123p
, 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.
Die folgende rekursive Funktion kann nützlich sein:
void bin(int n)
{
/* Step 1 */
if (n > 1)
bin(n/2);
/* Step 2 */
printf("%d", n % 2);
}
Ich habe die Top-Lösung für Größe und C ++ optimiert und bin zu dieser Lösung gekommen:
inline std::string format_binary(unsigned int x)
{
static char b[33];
b[32] = '\0';
for (int z = 0; z < 32; z++) {
b[31-z] = ((x>>z) & 0x1) ? '1' : '0';
}
return b;
}
std::string
) verwenden möchten , können Sie das static
Array auch entfernen. Am einfachsten wäre es, einfach das static
Qualifikationsmerkmal zu löschen und b
die Funktion lokal zu machen .
((x>>z) & 0x01) + '0'
ist ausreichend.
Dieser Ansatz hat als Attribute:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define for_endian(size) for (int i = 0; i < size; ++i)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define for_endian(size) for (int i = size - 1; i >= 0; --i)
#else
#error "Endianness not detected"
#endif
#define printb(value) \
({ \
typeof(value) _v = value; \
__printb((typeof(_v) *) &_v, sizeof(_v)); \
})
void __printb(void *value, size_t size)
{
uint8_t byte;
size_t blen = sizeof(byte) * 8;
uint8_t bits[blen + 1];
bits[blen] = '\0';
for_endian(size) {
byte = ((uint8_t *) value)[i];
memset(bits, '0', blen);
for (int j = 0; byte && j < blen; ++j) {
if (byte & 0x80)
bits[j] = '1';
byte <<= 1;
}
printf("%s ", bits);
}
printf("\n");
}
int main(void)
{
uint8_t c1 = 0xff, c2 = 0x44;
uint8_t c3 = c1 + c2;
printb(c1);
printb((char) 0xff);
printb((short) 0xff);
printb(0xff);
printb(c2);
printb(0x44);
printb(0x4411ff01);
printb((uint16_t) c3);
printf("\n");
return 0;
}
$ ./printb
11111111
11111111
00000000 11111111
00000000 00000000 00000000 11111111
01000100
00000000 00000000 00000000 01000100
01000100 00010001 11111111 00000001
00000000 01000011
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(unsigned int n)
{
unsigned int 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');
}
}
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(unsigned int x)
{
#define MAXLEN 8 // width of output format
#define MAXCNT 4 // count per printf statement
static char fmtbuf[(MAXLEN+1)*MAXCNT];
static int 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;
}
count
erreicht MAXCNT - 1
, würde das nächste Inkrement von count
es MAXCNT
anstelle 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
.
MAXCNT + 1
Aufrufe 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.
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.
Eine generische Konvertierung eines beliebigen Integraltyps in die binäre Zeichenfolgendarstellung unter Verwendung der Standardbibliothek :
#include <bitset>
MyIntegralType num = 10;
print("%s\n",
std::bitset<sizeof(num) * 8>(num).to_string().insert(0, "0b").c_str()
); // prints "0b1010\n"
Oder nur: std::cout << std::bitset<sizeof(num) * 8>(num);
Meine Lösung:
long unsigned int i;
for(i = 0u; i < sizeof(integer) * CHAR_BIT; i++) {
if(integer & LONG_MIN)
printf("1");
else
printf("0");
integer <<= 1;
}
printf("\n");
Basierend auf @ ideasman42 Vorschlag in seiner Antwort, das ist ein Makro , das bietet int8
, 16
, 32
& 64
Versionen, die Wiederverwendung den INT8
Makro um Wiederholungen zu vermeiden.
/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_SEPARATOR
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i) \
(((i) & 0x80ll) ? '1' : '0'), \
(((i) & 0x40ll) ? '1' : '0'), \
(((i) & 0x20ll) ? '1' : '0'), \
(((i) & 0x10ll) ? '1' : '0'), \
(((i) & 0x08ll) ? '1' : '0'), \
(((i) & 0x04ll) ? '1' : '0'), \
(((i) & 0x02ll) ? '1' : '0'), \
(((i) & 0x01ll) ? '1' : '0')
#define PRINTF_BINARY_PATTERN_INT16 \
PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_SEPARATOR PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
PRINTF_BINARY_PATTERN_INT16 PRINTF_BINARY_SEPARATOR PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64 \
PRINTF_BINARY_PATTERN_INT32 PRINTF_BINARY_SEPARATOR PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */
#include <stdio.h>
int main() {
long long int flag = 1648646756487983144ll;
printf("My Flag "
PRINTF_BINARY_PATTERN_INT64 "\n",
PRINTF_BYTE_TO_BINARY_INT64(flag));
return 0;
}
Dies gibt aus:
My Flag 0001011011100001001010110111110101111000100100001111000000101000
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:
My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
oder
My Flag 00010110 11100001 00101011 01111101 01111000 10010000 11110000 00101000
Verwenden:
char buffer [33];
itoa(value, buffer, 2);
printf("\nbinary: %s\n", buffer);
Weitere Informationen finden Sie unter Drucken von Binärzahlen über printf .
void print_ulong_bin(const unsigned long * const var, int bits) {
int i;
#if defined(__LP64__) || defined(_LP64)
if( (bits > 64) || (bits <= 0) )
#else
if( (bits > 32) || (bits <= 0) )
#endif
return;
for(i = 0; i < bits; i++) {
printf("%lu", (*var >> (bits - 1 - i)) & 0x01);
}
}
sollte funktionieren - ungetestet.
/* 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" */
Als nächstes wird Ihnen das Speicherlayout angezeigt:
#include <limits>
#include <iostream>
#include <string>
using namespace std;
template<class T> string binary_text(T dec, string byte_separator = " ") {
char* pch = (char*)&dec;
string res;
for (int i = 0; i < sizeof(T); i++) {
for (int j = 1; j < 8; j++) {
res.append(pch[i] & 1 ? "1" : "0");
pch[i] /= 2;
}
res.append(byte_separator);
}
return res;
}
int main() {
cout << binary_text(5) << endl;
cout << binary_text(.1) << endl;
return 0;
}
Hier ist eine kleine Variation der paniq -Lösung, die Vorlagen verwendet, um das Drucken von 32- und 64-Bit-Ganzzahlen zu ermöglichen:
template<class T>
inline std::string format_binary(T x)
{
char b[sizeof(T)*8+1] = {0};
for (size_t z = 0; z < sizeof(T)*8; z++)
b[sizeof(T)*8-1-z] = ((x>>z) & 0x1) ? '1' : '0';
return std::string(b);
}
Und kann verwendet werden wie:
unsigned int value32 = 0x1e127ad;
printf( " 0x%x: %s\n", value32, format_binary(value32).c_str() );
unsigned long long value64 = 0x2e0b04ce0;
printf( "0x%llx: %s\n", value64, format_binary(value64).c_str() );
Hier ist das Ergebnis:
0x1e127ad: 00000001111000010010011110101101
0x2e0b04ce0: 0000000000000000000000000000001011100000101100000100110011100000