C veya C ++ 'da ikili değişmez kullanabilir miyim?


191

İkili bir sayı ile çalışmam gerekiyor.

Yazmayı denedim:

const x = 00010000;

Ama işe yaramadı.

Ben aynı değeri olan onaltılık bir sayı kullanabilirsiniz biliyorum 00010000, ama ikili sayılar için C ++ bir tür olup olmadığını bilmek istiyorum ve yoksa, benim sorun için başka bir çözüm var mı?


51
Bunun 00010000sekizli olduğunu biliyorsun , değil mi? (Ve beyanınızda bir tür eksik.)
Keith Thompson

Burada modern yol C ++ değişmez kullanarak.
Lol4t0

2
C ++ 14 bunun için bir özellik ekledi. Alt kısımda daha fazla ayrıntı için yeni yanıtımı görün. Tabii ki, onu uygulayan bir derleyici gerektirir.
lpapp

1
@FormlessCloud: Bunlar C ve C ++ standartlarında verilen sözdizimi kurallarıdır ( 0byalnızca C ++ 14'te görünür). Belirsiz olacak şekilde tasarlanmıştır.
Keith Thompson

Yanıtlar:


70

Sen edebilirsiniz kullanmakBOOST_BINARY C ++ 0x beklerken. :) BOOST_BINARYtartışmalı olarak C programlarında da kullanılabildiği sürece şablon uygulaması üzerinde bir avantaja sahiptir (% 100 önişlemci güdümlüdür.)

Tersi yapmak için (yani bir sayıyı ikili biçimde yazdırmak için), taşınabilir olmayan itoaişlevi kullanabilir veya kendiniz uygulayabilirsiniz .

Ne yazık ki (çünkü STL akışlarla biçimlendirme tabanını 2 yapamaz setbasesadece namus bazlar 8, 10 ve 16 olacak), fakat olabilir bir birini kullanabilirsiniz std::stringsürümünü itoa, ya da (daha özlü, henüz marjinal az verimli) std::bitset.

#include <boost/utility/binary.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <bitset>
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
  unsigned short b = BOOST_BINARY( 10010 );
  char buf[sizeof(b)*8+1];
  printf("hex: %04x, dec: %u, oct: %06o, bin: %16s\n", b, b, b, itoa(b, buf, 2));
  cout << setfill('0') <<
    "hex: " << hex << setw(4) << b << ", " <<
    "dec: " << dec << b << ", " <<
    "oct: " << oct << setw(6) << b << ", " <<
    "bin: " << bitset< 16 >(b) << endl;
  return 0;
}

üretir:

hex: 0012, dec: 18, oct: 000022, bin:            10010
hex: 0012, dec: 18, oct: 000022, bin: 0000000000010010

Ayrıca ilginç bir tartışma için Herb Sutter'ın Manor Farm'ın String Formatter'lerini okuyun .


2
Bağlantı verdiğiniz sayfanın söylediği gibi, setbase ile yalnızca 8, 10 veya 16 kullanabilirsiniz. Ancak:int main() { cout << bitset<8>(42); }

@Roger bitsetbahşiş için teşekkürler setbase, yorumunuzu görmeden önce biraz düzelttim .
vladr

İşte c ++ 11'deki kullanıcı tanımlı değişmezler hakkında bir eğitim: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii . Açıkça c ++ 1y (aka c ++ 14) standartta ikili değişmezleri içerecektir.
cheshirekow

275

GCC kullanıyorsanız, bunun için bir GCC uzantısı ( C ++ 14 standardında bulunur ) kullanabilirsiniz:

int x = 0b00010000;

2
Diğer birkaç derleyici, taban 2'deki sayıları ifade etmenin bu veya diğer benzer yollarına sahiptir
nategoose

4
Bu standartlaştırılmış olması güzel olurdu, ancak clang aynı gösterimi destekler.
Polemon

14
Clang, GCC ve TCC'de çalışır. PCC'de çalışmaz. Test edilecek başka bir derleyicim yok.
Michas

6
Onu destekleyen bir dizi gömülü sistem derleyicisi gördüm. Standart bir dil özelliği olmamasının özel bir nedeni olduğunu bilmiyorum.
supercat


98

İkili değişmez değerleri kullanabilirsiniz. C ++ 14'te standartlaştırılmıştır. Örneğin,

int x = 0b11000;

GCC'de destek

GCC'de destek , C dil ailesine ek olarak GCC 4.3'te (bkz. Https://gcc.gnu.org/gcc-4.3/changes.html ) başladı (bkz. Https://gcc.gnu.org/onlinedocs/gcc/ C-Extensions.html # C-Extensions ), ancak GCC 4.9'dan beri artık bir C ++ 14 özelliği veya bir uzantı olarak tanınıyor (bkz. GCC ikili değişmezleriyle C ++ 14 olanlar arasındaki fark? )

Visual Studio'da Destek

Visual Studio'da destek Visual Studio 2015 Önizleme'de başladı (bkz. Https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).


5
Her parçayı ayırmak için 'kullanabilirsiniz: "0b0000'0100'0100'0001
camino

1
@camino Güzel ilk kaybedebilirsiniz "
Nikos

Bu kabul edilen cevap olmalı. Diğer cevapların çoğu sooo modası geçmiş.
Alex

73
template<unsigned long N>
struct bin {
    enum { value = (N%10)+2*bin<N/10>::value };
} ;

template<>
struct bin<0> {
    enum { value = 0 };
} ;

// ...
    std::cout << bin<1000>::value << '\n';

Değişmez kelimenin en sol basamağı hala 1 olmalıdır, ancak yine de olmalıdır.


4
Daha iyi sürüm: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valueve bazı hata denetimi)

Kendi özdeş cevabımı göndermeden önce bir şekilde bunu kaçırdım. Ama benimki baştaki rakam 1 değil, 0 olmalı.
Mark Ransom

4
Bu şablon fikrinin daha iyi bir sürümü: code.google.com/p/cpp-binary-constants
Valentin Galea

@ValentinGalea - Google sürümü neden bundan daha iyi?
AJ

Bu çok etkileyici. Çok fazla sayıda bit için işe yaramıyor.
Kuantum Fizikçisi

31

Çoğu derleyicinin (C / C ++ standartları) böyle bir özelliği olmasa da , birkaç derleyici (genellikle mikro denetleyiciler için olanlar ) sayıdan önce "0b ..." ön ekiyle gerçek ikili sayıları tanıma özelliğine sahiptir . durum, işte benim alternatif çözümüm:

#define B_0000    0
#define B_0001    1
#define B_0010    2
#define B_0011    3
#define B_0100    4
#define B_0101    5
#define B_0110    6
#define B_0111    7
#define B_1000    8
#define B_1001    9
#define B_1010    a
#define B_1011    b
#define B_1100    c
#define B_1101    d
#define B_1110    e
#define B_1111    f

#define _B2H(bits)    B_##bits
#define B2H(bits)    _B2H(bits)
#define _HEX(n)        0x##n
#define HEX(n)        _HEX(n)
#define _CCAT(a,b)    a##b
#define CCAT(a,b)   _CCAT(a,b)

#define BYTE(a,b)        HEX( CCAT(B2H(a),B2H(b)) )
#define WORD(a,b,c,d)    HEX( CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))) )
#define DWORD(a,b,c,d,e,f,g,h)    HEX( CCAT(CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))),CCAT(CCAT(B2H(e),B2H(f)),CCAT(B2H(g),B2H(h)))) )

// Using example
char b = BYTE(0100,0001); // Equivalent to b = 65; or b = 'A'; or b = 0x41;
unsigned int w = WORD(1101,1111,0100,0011); // Equivalent to w = 57155; or w = 0xdf43;
unsigned long int dw = DWORD(1101,1111,0100,0011,1111,1101,0010,1000); //Equivalent to dw = 3745774888; or dw = 0xdf43fd28;

Dezavantajları (çok büyük olanlar değil):

  • İkili sayılar 4'e 4 olarak gruplanmalıdır;
  • İkili değişmezler yalnızca işaretsiz tam sayı olmalıdır;

Avantajları :

  • Toplam önişlemci tarafından çalıştırılabilir, çalıştırılabilir programa spending processor timeanlamsız işlemlerde ( like "?.. :..", "<<", "+") değil ( son uygulamada yüzlerce kez gerçekleştirilebilir);
  • "mainly in C"Derleyiciler ve C ++ da çalışır ( template+enum solution works only in C++ compilers);
  • "Değişmez sabit" değerleri ifade etmek için sadece "uzun" sınırlaması vardır. Eğer çözüm ayrıştırılarak sabit değerler ifade edilmiş olsaydı, erken yaş sınırlaması (genellikle 8 bit: 0-255) olurdu."enum solution" (usually 255 = reach enum definition limit)Derleyicideki "değişmez sabit" sınırlamaların , daha uzun sayılara izin ;
  • Diğer bazı çözümler, uzun veya several header files(çoğu durumda kolayca okunamayan ve anlaşılamayan ) dahil olmak üzere abartılı sayıda (benim görüşüme göre çok fazla tanım) çok sayıda sabit tanım gerektirir ve projenin,"BOOST_BINARY()" ;
  • Çözümün basitliği: diğer durumlar için kolayca okunabilir, anlaşılabilir ve ayarlanabilir (8'den 8'e kadar gruplama için genişletilebilir);

Örneğin neden B_0100kullanılmıyor (yerine 0100)? Örneğin char b = BYTE(0100,0001);.
Peter Mortensen

@PeterMortensen B_, _B2Hönişlemci işlevi tarafından eklenir .
mxmlnkn

20

Bu konu size yardımcı olabilir.

/* Helper macros */
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)

/* User macros */
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
+ B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))


#include <stdio.h>

int main(void)
{
    // 261, evaluated at compile-time
    unsigned const number = B16(00000001,00000101);

    printf("%d \n", number);
    return 0;
}

İşe yarıyor! (Tüm krediler Tom Torfs'a gider.)


gerçekten anlamadım (programlamada acemi ve özel olarak C ++) ama ilginç görünüyor bu yüzden biraz daha C ++ çalışmalarından sonra anlamaya çalışacağım, teşekkürler
hamza 0

3
B8 makrosu, "ikili" değişmez değeri onaltılı bir değişmez değere dönüştürerek ve her 4. bitte bir ayıklayarak çalışır.
dan04

Acaba 0x ## n ## LU ne anlama geliyor? Böyle bir sözdizimiyle hiç karşılaşmadım.
Federico A.Ramponi

@hamza: gerçekten karmaşık. Ama anlamanız gereken şey sadece #include <stdio> 'dan.
Federico A.Ramponi

8
@Federico: ##Önişlemci operatörü belirteçleri birbirine yapıştırır. Yani, bu durumda, ararsanız HEX__(10), genişler 0x10LU.
James McNellis

18

Daha önce yanıtlandığı gibi, C standartlarının doğrudan ikili sayılar yazmanın bir yolu yoktur. Ancak derleyici uzantıları vardır ve görünüşe göre C ++ 140b ikili önek . (Bu cevabın ilk olarak 2010 yılında gönderildiğini unutmayın.)

Popüler bir çözüm, yardımcı makroları içeren bir başlık dosyası eklemektir . Kolay bir seçenek de tüm 8 bitlik desenler için makro tanımları içeren bir dosya oluşturmaktır, örneğin:

#define B00000000 0
#define B00000001 1
#define B00000010 2

Bu sadece 256 #defines ile sonuçlanır ve 8 bitlik ikili sabitlerden daha fazlasına ihtiyaç duyulursa, bu tanımlar, muhtemelen yardımcı makrolarla (ör.BIN16(B00000001,B00001010) ) . (Her 16 bit için ayrı ayrı makrolara sahip olmak, 32 bitlik olsun, değer mantıklı değil.)

Tabii ki dezavantajı, bu sözdiziminin tüm önde gelen sıfırları yazmayı gerektirmesidir, ancak bu aynı zamanda bit bayraklarını ve donanım kayıtlarının içeriğini ayarlamak gibi kullanımlar için daha net hale getirebilir. Bu özelliği olmayan bir sözdizimiyle sonuçlanan işlev benzeri bir makro için, bkz bithacks.h. Yukarıda bağlantı.


2
Peki, bir makro için tüm makrolara sahipseniz CPP'nin ne kadar büyük bir dosyayı okuması gerekir long long int?
wilhelmtell

3
@wilhelmtell: “Tüm 8 bitlik desenleri” (= 256 satır) belirleyip bunlardan daha büyük miktarları birleştirmeyi önerdiğimde bunun önemi nedir? Kabul edilen cevabın BOOST_BINARY bile başlığındaki tüm 8 bitlik kalıpları tanımlar…
Arkku

16

C ++ aşırı mühendislik zihniyeti, buradaki diğer cevaplarda zaten iyi bir şekilde açıklanmıştır. İşte bunu bir C, basit tutmak ffs zihniyet ile yapmaya çalışıyorum:

unsigned char x = 0xF; // binary: 00001111

12

C'nin saf ikili sayılar için yerel gösterimi yoktur. Yapabileceğiniz en iyi şey burada ya olacağını sekizlik (örn 07777ait) onaltılık (örn 0xfff).


11

C ++ 'da 22 bite kadar almak için bu soruda bulunan işlevi kullanabilirsiniz . İşte bağlantıdan uygun şekilde düzenlenmiş kod:

template< unsigned long long N >
struct binary
{
  enum { value = (N % 8) + 2 * binary< N / 8 > :: value } ;
};

template<>
struct binary< 0 >
{
  enum { value = 0 } ;
};

Böylece böyle bir şey yapabilirsiniz binary<0101011011>::value.


7

Çalışabileceğiniz en küçük birim bir bayttır ( chartiptedir). Bitsel işleçleri kullanarak bitlerle çalışabilirsiniz.

Tamsayı değişmez değerlerine gelince, yalnızca ondalık (taban 10), sekizli (taban 8) veya onaltılık (taban 16) sayılarla çalışabilirsiniz. C veya C ++ 'da ikili (taban 2) değişmez değeri yoktur.

Sekizlik sayıların önüne 0ve onaltılık sayıların önüne eklenir 0x. Ondalık sayıların öneki yoktur.

C ++ 0x ile kullanıcı tanımlı değişmez değerler aracılığıyla istediğinizi yapabilirsiniz .


en azından bir baskıda veya cout fonksiyonunda onaltılı bir İkili değerini gösterebilir miyim?
hamza

Evet <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr

5
Bazı C derleyicileri ikili değişmez değerler için 0b100101'i destekler, ancak maalesef standart olmayan bir uzantıdır.
Joey Adams

3
Standartta tanımlanmamış olsa da, bazı derleyiciler (özellikle mikro denetleyiciler ve gömülü sistemler için olanlar) formdaki ikili sözdizimini 0b00101010kolaylık olarak eklediğini unutmayın . SDCC birdir ve eminim ki bunu yapan başkaları da vardır. (Düzenleme: Hah, beni dövdü, @Joey!)
Matt B.

5

Satır içi montajı şu şekilde de kullanabilirsiniz:

int i;

__asm {
    mov eax, 00000000000000000000000000000000b
    mov i,   eax
}

std::cout << i;

Tamam, biraz abartılı olabilir, ama işe yarıyor.


3
Çözümünüz çoklu platform değil. Birçok mimaride C'ye montaj kodu ekleyemezsiniz. Özellikle Microsoft Visual studio derleyicisinde (x86 32 bit için derlendiğinde) yapabilirsiniz. Ancak işlemcinizin 'eax' kaydı olup olmadığını nasıl anlarsınız? Cep telefonlarındaki ARM işlemcilerini, x64 işlemciyi vb. Düşünün. 'Eax'ları yoktur. MIPS işlemcisinde 'mov' komutu bile yok
DanielHsH

4

Diğer bazı cevaplara dayanarak, bu, yasadışı ikili değişmezleri olan programları reddedecektir. Baştaki sıfırlar isteğe bağlıdır.

template<bool> struct BinaryLiteralDigit;

template<> struct BinaryLiteralDigit<true> {
    static bool const value = true;
};

template<unsigned long long int OCT, unsigned long long int HEX>
struct BinaryLiteral {
    enum {
        value = (BinaryLiteralDigit<(OCT%8 < 2)>::value && BinaryLiteralDigit<(HEX >= 0)>::value
            ? (OCT%8) + (BinaryLiteral<OCT/8, 0>::value << 1)
            : -1)
    };
};

template<>
struct BinaryLiteral<0, 0> {
    enum {
        value = 0
    };
};

#define BINARY_LITERAL(n) BinaryLiteral<0##n##LU, 0x##n##LU>::value

Misal:

#define B BINARY_LITERAL

#define COMPILE_ERRORS 0

int main (int argc, char ** argv) {
    int _0s[] = { 0, B(0), B(00), B(000) };
    int _1s[] = { 1, B(1), B(01), B(001) };
    int _2s[] = { 2, B(10), B(010), B(0010) };
    int _3s[] = { 3, B(11), B(011), B(0011) };
    int _4s[] = { 4, B(100), B(0100), B(00100) };

    int neg8s[] = { -8, -B(1000) };

#if COMPILE_ERRORS
    int errors[] = { B(-1), B(2), B(9), B(1234567) };
#endif

    return 0;
}

3

İkili sayının "türü", herhangi bir ondalık, onaltılık veya sekizlik sayı ile aynıdır: int(hatta char, short, long long).

Bir sabit atadığınızda, onu 11011011 (merakla ve ne yazık ki) ile atayamazsınız, ancak hex kullanabilirsiniz. Hex, zihinsel olarak tercüme edilmesi biraz daha kolaydır. Nibbles (4 bit) halinde yığınlayın ve [0-9a-f] 'deki bir karaktere çevirin.


2

Bir bit kümesi kullanabilirsiniz

bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;

2

@ Renato-chandelier tarafından verilen iyi cevabı aşağıdaki desteği sağlayarak genişlettim:

  • _NIBBLE_(…) - 4 bit, argüman olarak 1 kemirmek
  • _BYTE_(…) - 8 bit, argüman olarak 2 nibble
  • _SLAB_(…) - 12 bit, argüman olarak 3 nibble
  • _WORD_(…) - 16 bit, argüman olarak 4 nibble
  • _QUINTIBBLE_(…) - 20 bit, argüman olarak 5 nibble
  • _DSLAB_(…) - 24 bit, argüman olarak 6 kemirmek
  • _SEPTIBBLE_(…) - 28 bit, argüman olarak 7 kemirmek
  • _DWORD_(…) - 32 bit, 8 argüman olarak

“Quintibble” ve “septibble” terimlerinden pek emin değilim. Eğer herhangi bir alternatif biliyorsa lütfen bana bildirin.

İşte yeniden yazılan makro:

#define __CAT__(A, B) A##B
#define _CAT_(A, B) __CAT__(A, B)

#define __HEX_0000 0
#define __HEX_0001 1
#define __HEX_0010 2
#define __HEX_0011 3
#define __HEX_0100 4
#define __HEX_0101 5
#define __HEX_0110 6
#define __HEX_0111 7
#define __HEX_1000 8
#define __HEX_1001 9
#define __HEX_1010 a
#define __HEX_1011 b
#define __HEX_1100 c
#define __HEX_1101 d
#define __HEX_1110 e
#define __HEX_1111 f

#define _NIBBLE_(N1) _CAT_(0x, _CAT_(__HEX_, N1))
#define _BYTE_(N1, N2) _CAT_(_NIBBLE_(N1), _CAT_(__HEX_, N2))
#define _SLAB_(N1, N2, N3) _CAT_(_BYTE_(N1, N2), _CAT_(__HEX_, N3))
#define _WORD_(N1, N2, N3, N4) _CAT_(_SLAB_(N1, N2, N3), _CAT_(__HEX_, N4))
#define _QUINTIBBLE_(N1, N2, N3, N4, N5) _CAT_(_WORD_(N1, N2, N3, N4), _CAT_(__HEX_, N5))
#define _DSLAB_(N1, N2, N3, N4, N5, N6) _CAT_(_QUINTIBBLE_(N1, N2, N3, N4, N5), _CAT_(__HEX_, N6))
#define _SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7) _CAT_(_DSLAB_(N1, N2, N3, N4, N5, N6), _CAT_(__HEX_, N7))
#define _DWORD_(N1, N2, N3, N4, N5, N6, N7, N8) _CAT_(_SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7), _CAT_(__HEX_, N8))

Ve burada Renault'nun örneği:

char b = _BYTE_(0100, 0001); /* equivalent to b = 65; or b = 'A'; or b = 0x41; */
unsigned int w = _WORD_(1101, 1111, 0100, 0011); /* equivalent to w = 57155; or w = 0xdf43; */
unsigned long int dw = _DWORD_(1101, 1111, 0100, 0011, 1111, 1101, 0010, 1000); /* Equivalent to dw = 3745774888; or dw = 0xdf43fd28; */

0

Sadece standart C ++ kütüphanesini kullanın:

#include <bitset>

Bir değişken türüne ihtiyacınız var std::bitset:

std::bitset<8ul> x;
x = std::bitset<8>(10);
for (int i = x.size() - 1; i >= 0; i--) {
      std::cout << x[i];
}

Bu örnekte, ben ikili formunu muhafaza 10içinde x.

8ulbitlerinizin boyutunu tanımlar, yani 7ulyedi bit ve benzeri anlamına gelir.



Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.