Je peux imprimer avec printf sous forme hexadécimale ou octale. Existe-t-il une balise de format à imprimer en base binaire ou arbitraire?
Je cours gcc.
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
Hacky mais travaille pour moi:
#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));
Pour les types multi-octets
printf("m: "BYTE_TO_BINARY_PATTERN" "BYTE_TO_BINARY_PATTERN"\n",
BYTE_TO_BINARY(m>>8), BYTE_TO_BINARY(m));
Malheureusement, vous avez besoin de toutes les citations supplémentaires. Cette approche présente les risques d'efficacité des macros (ne passez pas une fonction en tant qu'argument à BYTE_TO_BINARY
), mais évite les problèmes de mémoire et les invocations multiples de strcat dans certaines des autres propositions présentées ici.
Binaire d'impression pour tout type de données
//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("");
}
tester
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;
}
Voici un petit tour d'horizon pour démontrer des techniques pour faire ce que vous voulez.
#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;
}
Il n'y a pas de spécificateur de conversion binaire dans la glibc normalement.
Il est possible d’ajouter des types de conversion personnalisés à la famille de fonctions printf () de la glibc. Voir register_printf_function pour plus de détails. Vous pouvez ajouter une conversion personnalisée% b pour votre propre usage, si cela simplifie le code d'application pour le rendre disponible.
Voici un exemple sur la manière de mettre en œuvre un format printf personnalisé dans glibc.
Vous pourriez utiliser une petite table pour améliorer la vitesse1. Des techniques similaires sont utiles dans le monde intégré, par exemple, pour inverser un octet:
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 Je me réfère principalement aux applications embarquées où les optimiseurs ne sont pas si agressifs et où la différence de vitesse est visible.
D'après la réponse de @William Whyte, il s'agit d'une macro qui fournit les versions int8
, 16
, 32
& 64
, réutilisant la macro INT8
pour éviter les répétitions.
/* --- 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;
}
Cela génère:
My Flag 0001011011100001001010110111110101111000100100001111000000101000
Pour plus de lisibilité, vous pouvez ajouter un séparateur pour, par exemple:
My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
Voici une version de la fonction qui ne souffre pas de problèmes de réentrance ni de limites sur la taille/le type de l'argument:
#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;
}
Notez que ce code fonctionnerait aussi bien pour toute base entre 2 et 10 si vous venez de remplacer les 2 par la base désirée. L'utilisation est:
char tmp[FMT_BUF_SIZE];
printf("%s\n", binary_fmt(x, tmp));
Où x
est une expression intégrale.
Imprimer le bit le moins significatif et le décaler vers la droite. Cela jusqu’à ce que l’entier devienne zéro imprime la représentation binaire sans zéros mais dans l’ordre inverse. En utilisant la récursivité, la commande peut être corrigée assez facilement.
#include <stdio.h>
void print_binary(int number)
{
if (number) {
print_binary(number >> 1);
putc((number & 1) ? '1' : '0', stdout);
}
}
Pour moi, c'est l'une des solutions les plus propres au problème. Si vous aimez le préfixe 0b
et un caractère de fin de ligne, je vous suggère d’envelopper la fonction.
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;
}
Certaines exécutions prennent en charge "% b" bien que cela ne soit pas une norme.
Voir aussi ici pour une discussion intéressante:
http://bytes.com/forum/thread591027.html
HTH
Aucune des réponses précédemment affichées ne correspond exactement à ce que je cherchais, alors j’en ai écrit une. C'est super simple d'utiliser% B avec la 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);
}
Ce code doit gérer vos besoins jusqu’à 64 bits . J’ai créé 2 fonctions pBin & pBinFill. Les deux font la même chose, mais pBinFill remplit les espaces précédents avec fillChar . La fonction de test génère des données de test, puis les affiche à l'aide de la fonction.
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
Peut-être un peu OT, mais si vous avez besoin de cela uniquement pour le débogage afin de comprendre ou de retracer certaines opérations binaires que vous faites, vous pouvez jeter un oeil sur wcalc (une simple calculatrice à console). Avec les options -b, vous obtenez une sortie binaire.
par exemple.
$ wcalc -b "(256 | 3) & 0xff" = 0b11
Existe-t-il un convertisseur printf pour imprimer au format binaire?
La famille printf()
peut uniquement imprimer en bases 8, 10 et 16 en utilisant directement les spécificateurs standard. Je suggère de créer une fonction qui convertit le nombre en chaîne en fonction des besoins particuliers du code.
Pour imprimer dans n'importe quelle base [2-36]
Toutes les autres réponses à ce jour ont au moins une de ces limitations.
Utilisez la mémoire statique pour le tampon de retour. Ceci limite le nombre d'utilisations de la fonction en tant qu'argument à printf()
.
Allouez de la mémoire nécessitant le code d'appel pour libérer les pointeurs.
Exiger que le code appelant fournisse explicitement un tampon approprié.
Appelez printf()
directement. Cela oblige à créer une nouvelle fonction permettant de fprintf()
, sprintf()
, vsprintf()
, etc.
Utilisez une plage entière réduite.
Ce qui suit n'a aucun des limitations ci-dessus. Cela nécessite C99 ou une version ultérieure et l'utilisation de "%s"
. Il utilise un composé littéral pour fournir l'espace tampon. Il n’ya aucun problème avec plusieurs appels dans une 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;
}
Sortie
1020304 5060708
1000000100000001100000100 101000001100000011100001000
100401404
A2F44
Il n'y a pas de fonction de formatage dans la bibliothèque standard C pour sortir un binaire comme ça. Toutes les opérations de format prises en charge par la famille printf s’appliquent au texte lisible par l’homme.
La fonction récursive suivante pourrait être utile:
void bin(int n)
{
/* Step 1 */
if (n > 1)
bin(n/2);
/* Step 2 */
printf("%d", n % 2);
}
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');
}
}
J'ai optimisé la solution de pointe pour la taille et le C++, et je suis arrivé à cette solution:
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;
}
D'après la suggestion de @ ideasman42 dans sa réponse, il s'agit d'une macro qui fournit les versions int8
, 16
, 32
& 64
, réutilisant la macro INT8
pour éviter les répétitions.
/* --- 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;
}
Cela génère:
My Flag 0001011011100001001010110111110101111000100100001111000000101000
Pour plus de lisibilité, vous pouvez changer: #define PRINTF_BINARY_SEPARATOR
en #define PRINTF_BINARY_SEPARATOR ","
ou #define PRINTF_BINARY_SEPARATOR " "
Cela produira:
My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
ou
My Flag 00010110 11100001 00101011 01111101 01111000 10010000 11110000 00101000
Cette approche a pour attributs:
#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
J'ai utilisé une autre approche ( bitprint.h ) pour remplir un tableau avec tous les octets (sous forme de chaînes de bits) et les imprimer en fonction de l'octet d'entrée/index. Cela vaut la peine de jeter un coup d'œil.
Ma solution:
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");
Pas de moyen standard et portable.
Certaines implémentations fournissent itoa () , mais ce n’est pas le cas dans la plupart des cas, et son interface est un peu moche. Mais le code est derrière le lien et devrait vous permettre de mettre en place votre propre formateur assez facilement.
J'ai aimé le code de paniq, le tampon statique est une bonne idée. Cependant, cela échouera si vous voulez plusieurs formats binaires dans un seul printf () car il retourne toujours le même pointeur et écrase le tableau.
Voici un drop-in de style C qui fait pivoter le pointeur sur un tampon divisé.
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;
}
Une instruction de conversion générique de tout type intégral en représentation sous forme de chaîne binaire à l'aide de la bibliothèque standard:
#include <bitset>
MyIntegralType num = 10;
print("%s\n",
std::bitset<sizeof(num) * 8>(num).to_string().insert(0, "0b").c_str()
); // prints "0b1010\n"
Ou simplement:std::cout << std::bitset<sizeof(num) * 8>(num);
Voici comment je l'ai fait pour un int non signé
void printb(unsigned int v) {
unsigned int i, s = 1<<((sizeof(v)<<3)-1); // s = only most significant bit at 1
for (i = s; i; i>>=1) printf("%d", v & i || 0 );
}
Une petite fonction utilitaire en C pour faire cela tout en résolvant un problème de manipulation de bits. Ceci passe la chaîne vérifiant chaque bit défini en utilisant un masque (1 <
void
printStringAsBinary(char * input)
{
char * temp = input;
int i = 7, j =0;;
int inputLen = strlen(input);
/* Go over the string, check first bit..bit by bit and print 1 or 0
**/
for (j = 0; j < inputLen; j++) {
printf("\n");
while (i>=0) {
if (*temp & (1 << i)) {
printf("1");
} else {
printf("0");
}
i--;
}
temp = temp+1;
i = 7;
printf("\n");
}
}
Suivant vous montrera la disposition de la mémoire:
#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;
}
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);
}
}
devrait fonctionner - non testé.
#include <stdio.h>
#include <conio.h>
void main()
{
clrscr();
printf("Welcome\n\n\n");
unsigned char x='A';
char ch_array[8];
for(int i=0; x!=0; i++)
{
ch_array[i] = x & 1;
x = x >>1;
}
for(--i; i>=0; i--)
printf("%d", ch_array[i]);
getch();
}
Encore une autre approche pour imprimer en binaire: Convertit l’entier en premier .
Pour imprimer 6
en binaire, remplacez 6
par 110
, puis imprimez "110"
.
Contourne les problèmes char buf[]
.printf()
Les spécificateurs de format, les drapeaux et les champs tels que "%08lu"
, "%*lX"
sont toujours facilement utilisables.
Non seulement binaire (base 2), cette méthode peut être étendue à d’autres bases jusqu’à 16.
Limité aux valeurs entières les plus petites.
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
unsigned long char_to_bin10(char ch) {
unsigned char uch = ch;
unsigned long sum = 0;
unsigned long power = 1;
while (uch) {
if (uch & 1) {
sum += power;
}
power *= 10;
uch /= 2;
}
return sum;
}
uint64_t uint16_to_bin16(uint16_t u) {
uint64_t sum = 0;
uint64_t power = 1;
while (u) {
if (u & 1) {
sum += power;
}
power *= 16;
u /= 2;
}
return sum;
}
void test(void) {
printf("%lu\n", char_to_bin10(0xF1));
// 11110001
printf("%" PRIX64 "\n", uint16_to_bin16(0xF731));
// 1111011100110001
}
Voici une petite variante de la solution de paniq qui utilise des modèles pour permettre l’impression d’entiers 32 et 64 bits:
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);
}
Et peut être utilisé comme:
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() );
Voici le résultat:
0x1e127ad: 00000001111000010010011110101101
0x2e0b04ce0: 0000000000000000000000000000001011100000101100000100110011100000
Je veux juste poster ma solution. Il est utilisé pour obtenir des zéros et des octets, mais l'appel de cette fonction plusieurs fois peut être utilisé pour des blocs de données plus grands. Je l'utilise pour des structures de 128 bits ou plus. Vous pouvez également le modifier pour qu'il utilise size_t en tant que paramètre d'entrée et pointeur sur les données à imprimer, de sorte qu'il puisse être indépendant de la taille. Mais ça marche pour moi, quitte bien comme ça.
void print_binary(unsigned char c)
{
unsigned char i1 = (1 << (sizeof(c)*8-1));
for(; i1; i1 >>= 1)
printf("%d",(c&i1)!=0);
}
void get_binary(unsigned char c, unsigned char bin[])
{
unsigned char i1 = (1 << (sizeof(c)*8-1)), i2=0;
for(; i1; i1>>=1, i2++)
bin[i2] = ((c&i1)!=0);
}
/* 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" */
Il est également possible de convertir le nombre au format hexadécimal, puis de décoder chaque chiffre hexadécimal en quatre "bits" (uns et zéros). sprintf
peut effectuer des opérations de bits pour nous:
const char* binary(int n) {
static const char binnums[16][5] = { "0000","0001","0010","0011",
"0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };
static const char* hexnums = "0123456789abcdef";
static char inbuffer[16], outbuffer[4*16];
const char *i;
sprintf(inbuffer,"%x",n); // hexadecimal n -> inbuffer
for(i=inbuffer; *i!=0; ++i) { // for each hexadecimal cipher
int d = strchr(hexnums,*i) - hexnums; // store its decimal value to d
char* o = outbuffer+(i-inbuffer)*4; // shift four characters in outbuffer
sprintf(o,"%s",binnums[d]); // place binary value of d there
}
return strchr(outbuffer,'1'); // omit leading zeros
}
puts(binary(42)); // outputs 101010
Utilisation:
char buffer [33];
itoa(value, buffer, 2);
printf("\nbinary: %s\n", buffer);
Pour plus de réf., Voir Comment imprimer un nombre binaire via printf.
Faites une fonction et appelez-la
display_binary(int n)
{
long int arr[32];
int arr_counter=0;
while(n>=1)
{
arr[arr_counter++]=n%2;
n/=2;
}
for(int i=arr_counter-1;i>=0;i--)
{
printf("%d",arr[i]);
}
}
Peut-être que quelqu'un trouvera cette solution utile:
void print_binary(int number, int num_digits) {
int digit;
for(digit = num_digits - 1; digit >= 0; digit--) {
printf("%c", number & (1 << digit) ? '1' : '0');
}
}
void DisplayBinary(unsigned int n)
{
int l = sizeof(n) * 8;
for (int i = l - 1 ; i >= 0; i--) {
printf("%x", (n & (1 << i)) >> i);
}
}
void DisplayBinary(int n)
{
int arr[8];
int top =-1;
while (n)
{
if (n & 1)
arr[++top] = 1;
else
arr[++top] = 0;
n >>= 1;
}
for (int i = top ; i > -1;i--)
{
printf("%d",arr[i]);
}
printf("\n");
}
Solution rapide et facile:
void printbits(my_integer_type x)
{
for(int i=sizeof(x)<<3; i; i--)
putchar('0'+((x>>(i-1))&1));
}
Fonctionne pour tout type de taille et pour les ints signés et non signés. Le '& 1' est nécessaire pour gérer les entrées signées, car le décalage peut entraîner une extension de signe.
Il y a tellement de façons de faire cela. En voici une très simple pour imprimer 32 bits ou n bits à partir d'un type 32 bits signé ou non signé (ne pas mettre un négatif si signé, mais simplement imprimer les bits réels) et ne pas renvoyer de chariot. Notez que i est décrémenté avant le décalage de bit:
#define printbits_n(x,n) for (int i=n;i;i--,putchar('0'|(x>>i)&1))
#define printbits_32(x) printbits_n(x,32)
Qu'en est-il de retourner une chaîne avec les bits à stocker ou à imprimer plus tard? Vous pouvez soit allouer la mémoire, la restituer et l'utilisateur la libérer, ou vous renvoyer une chaîne statique, mais elle sera obstruée si elle est appelée à nouveau ou par un autre thread. Les deux méthodes présentées:
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;
}
Appeler avec:
// 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);
Même pour les bibliothèques d'exécution prenant en charge% b, il semble que ce ne soit que pour les valeurs entières.
Si vous voulez imprimer des valeurs à virgule flottante en binaire, j'ai écrit du code que vous pouvez trouver à http://www.exploringbinary.com/converting-floating-point-numbers-to-binary-strings-in-c/ .
En voici un très simple:
int print_char_to_binary(char ch)
{
int i;
for (i=7; i>=0; i--)
printf("%hd ", ((ch & (1<<i))>>i));
printf("\n");
return 0;
}
Existe-t-il un convertisseur printf pour imprimer au format binaire?
Il n'y a pas de spécificateur de format printf standard permettant d'obtenir une sortie "binaire". Voici l'alternative que j'ai imaginée quand j'en avais besoin.
Mine fonctionne pour toute base comprise entre 2 et 36. Elle insère les chiffres dans les cadres d'appel des invocations récursives, jusqu'à atteindre un chiffre plus petit que la base. Ensuite, il "traverse" en arrière, remplissant la mémoire tampon en avant, et en revenant. La valeur de retour est la taille utilisée ou -1 si le tampon n'est pas assez grand pour contenir la chaîne.
int conv_rad (int num, int rad, char *s, int n) {
char *vec = "0123456789" "ABCDEFGHIJKLM" "NOPQRSTUVWXYZ";
int off;
if (n == 0) return 0;
if (num < rad) { *s = vec[num]; return 1; }
off = conv_rad(num/rad, rad, s, n);
if ((off == n) || (off == -1)) return -1;
s[off] = vec[num%rad];
return off+1;
}
Une grosse mise en garde: Cette fonction a été conçue pour être utilisée avec des chaînes de style "Pascal" qui portent leur longueur. Par conséquent, conv_rad
, tel qu’écrit, ne met pas fin au tampon. Pour des utilisations plus générales du C, il aura probablement besoin d'un simple wrapper pour terminer nul. Ou pour l’impression, il suffit de changer les assignations en putchar()
s.
void binario(int num) {
for(int i=0;i<32;i++){
(num&(1<i))? printf("1"):
printf("0");
}
printf("\n");
}
La fonction suivante retourne une représentation binaire d'un entier non signé donné en utilisant l'arithmétique de pointeur sans zéros:
const char* toBinaryString(unsigned long num)
{
static char buffer[CHAR_BIT*sizeof(num)+1];
char* pBuffer = &buffer[sizeof(buffer)-1];
do *--pBuffer = '0' + (num & 1);
while (num >>= 1);
return pBuffer;
}
Notez qu'il n'est pas nécessaire de définir explicitement NUL
terminator, car buffer
représente un objet avec durée de stockage statique , déjà rempli de zéros.
Cela peut être facilement adapté à unsigned long long
(ou à un autre entier non signé) en modifiant simplement le type du paramètre formel num
.
Le CHAR_BIT
nécessite que <limits.h>
soit inclus.
Voici un exemple d'utilisation:
int main(void)
{
printf(">>>%20s<<<\n", toBinaryString(1));
printf(">>>%-20s<<<\n", toBinaryString(254));
return 0;
}
avec sa sortie désirée comme:
>>> 1<<<
>>>11111110 <<<
void PrintBinary( int Value, int Places, char* TargetString)
{
int Mask;
Mask = 1 << Places;
while( Places--) {
Mask >>= 1; /* Preshift, because we did one too many above */
*TargetString++ = (Value & Mask)?'1':'0';
}
*TargetString = 0; /* Null terminator for C string */
}
La fonction appelante "possède" la chaîne ...:
char BinaryString[17];
...
PrintBinary( Value, 16, BinaryString);
printf( "yadda yadda %s yadda...\n", BinaryString);
Selon votre CPU, la plupart des opérations dans PrintBinary sont rendues en une ou très peu d'instructions machine.
Ce n'est peut-être pas très efficace mais c'est assez simple. Essaye ça:
tmp1 = 1;
while(inint/tmp1 > 1) {
tmp1 <<= 1;
}
do {
printf("%d", tmp2=inint/tmp1);
inint -= tmp1*tmp2;
} while((tmp1 >>= 1) > 0);
printf(" ");
Utilisez la fonction ci-dessous:
void conbin(int num){
if(num != 0)
{
conbin(num >> 1);
if (num & 1){
printf("1");
}
else{
printf("0");
}
}
}