Препроцессор, дающий компиляцию при объявлении unsigned int x и инициализации с двоичной константой [duplicate]

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

171
задан Peter Mortensen 12 September 2015 в 17:43
поделиться

16 ответов

Вы можете использовать найденную функцию в этом вопросе , чтобы получить до 22 бит в C ++. Вот код из ссылки, соответствующим образом отредактированный:

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

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

Итак, вы можете сделать что-то вроде binary<0101011011>::value.

66
ответ дан Community 19 August 2018 в 01:50
поделиться
  • 1
    Поскольку на самой странице, на которую вы ссылаетесь, вы можете использовать только 8, 10 или 16 с помощью setbase. Однако: int main() { cout << bitset<8>(42); } – user 10 April 2010 в 03:40
  • 2
    @Roger благодарит за bitset отзыв, я уже исправил бит о setbase, прежде чем увидел ваш комментарий. – vladr 10 April 2010 в 03:50
  • 3
    +1 Я предпочитаю ваш ответ через @ wilhelmtell, потому что ведущие 0 не являются значимыми, а 1s - – BlackBear 27 September 2011 в 14:54
  • 4
    не нормально, если вы используете встроенную систему ... – Thomas 16 November 2012 в 11:39
  • 5
    Вот учебник по пользовательским литералам в c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-partiiii . Очевидно, что c ++ 1y (a.k.a. c ++ 14) будет включать бинарные литералы в стандарте. – cheshirekow 14 September 2013 в 22:06
  • 6
    @BlackBear, на самом деле, я думаю, что они есть. – imallett 3 July 2015 в 20:03
  • 7
    Я бы хотел, чтобы это можно было заменить на принятый ответ. – Jonathan Mee 4 February 2016 в 17:50
  • 8
    это должен быть любимый ответ – 3DSC 21 January 2018 в 16:03
65
ответ дан Community 30 October 2018 в 13:28
поделиться

Как уже было сказано, стандарты C не имеют возможности напрямую писать двоичные числа. Однако есть расширения компилятора, и, судя по всему, C ++ 14 содержит префикс 0b для двоичного кода. (Обратите внимание, что этот ответ был первоначально опубликован в 2010 году.)

Одним из распространенных способов решения является включение файла заголовка со вспомогательными макросами . Одним из простых вариантов является создание файла, который включает определения макросов для всех 8-битных шаблонов, например:

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

. Это приводит только к 256 #define s, а если больше 8-битного двоичного кода необходимы константы, эти определения могут быть объединены со сдвигами и OR, возможно с вспомогательными макросами (например, BIN16(B00000001,B00001010)). (Имея индивидуальные макросы для каждого 16-битного, не говоря уже о 32-битном, значение не правдоподобно.)

Конечно, недостатком является то, что этот синтаксис требует записи всех ведущих нулей, но это также может сделать это более понятный для использования, как установка битовых флагов и содержимого аппаратных регистров. Для функционально-подобного макроса, приводящего к синтаксису без этого свойства, см. bithacks.h, приведенную выше.

15
ответ дан Arkku 19 August 2018 в 01:50
поделиться
  • 1
    Итак, насколько большой файл должен был читать CPP, если бы у вас были все макросы для long long int? – wilhelmtell 10 April 2010 в 03:03
  • 2
    @wilhelmtell: И какова значимость этого, когда я задал «все 8-битные шаблоны» (= 256 строк) и предложил объединить большие количества из них? Даже BOOST_BINARY принятого ответа определяет все 8-битные шаблоны в заголовке ... – Arkku 10 April 2010 в 15:12
  • 3
    (Мне немного странно, что этот ответ по-прежнему получает downvotes два года спустя, особенно когда мое первое предложение состоит в том, чтобы включить заголовок библиотеки, существенно не отличающийся от принятого ответа, и мое второе предложение состоит в том, чтобы генерировать 256 макросов для 8-битные константы, что меньше #define, чем в заголовке BOOST_BINARY ...) – Arkku 29 June 2012 в 16:15

Наименьшая единица, с которой вы можете работать, - это байт (который имеет тип char). Вы можете работать с битами, хотя с помощью побитовых операторов.

Что касается целых литералов, вы можете работать только с десятичными (базовыми 10), восьмеричными (базовыми 8) или шестнадцатеричными (базовыми 16) числами. В C или C ++ нет бинарных (базовых 2) литералов.

Октальные числа имеют префикс 0, а шестнадцатеричные числа имеют префикс 0x. Десятичные числа не имеют префикса.

В C ++ 0x вы сможете делать то, что хотите, через пользовательские литералы .

7
ответ дан Brian R. Bondy 19 August 2018 в 01:50
поделиться
  • 1
    могу ли я хотя бы показать двоичное значение шестнадцатеричного числа в функции print или cout? – hamza 10 April 2010 в 02:48
  • 2
    Да, вы можете <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug> – vladr 10 April 2010 в 03:05
  • 3
    Некоторые компиляторы C поддерживают 0b100101 для двоичных литералов, но, к сожалению, это нестандартное расширение. – Joey Adams 10 April 2010 в 04:10
  • 4
    Обратите внимание, что, хотя он не определен в стандарте, некоторые компиляторы (особенно для микроконтроллеров и встроенных систем) добавляют синтаксис для двоичного кода в форме 0b00101010 в качестве удобства. SDCC - один, и я уверен, что есть и другие, которые тоже делают. (Править: Ха, избили меня, @ Джо!) – Matt B. 10 April 2010 в 04:13
  • 5
    И GCC тоже, начиная с 4.3: gcc.gnu.org/gcc-4.3/changes.html – Matt B. 10 April 2010 в 04:20

Слишком сложное мышление C ++ уже хорошо объяснено в других ответах здесь. Вот моя попытка сделать это с помощью C, keep-it-simple-ffs mindset:

unsigned char x = 0xF; // binary: 00001111
12
ответ дан Craig 19 August 2018 в 01:50
поделиться

Вы можете использовать битсет

bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;
2
ответ дан Deqing 19 August 2018 в 01:50
поделиться

Этот поток может помочь.

/* 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;
}

Он работает! (Все кредиты отправляются Тому Торфсу.)

19
ответ дан Federico A. Ramponi 19 August 2018 в 01:50
поделиться
  • 1
    я действительно не понял (я новичок в программировании и особенно на C ++), но кажется интересным, поэтому я попытаюсь понять его после нескольких исследований на C ++, спасибо – hamza 10 April 2010 в 01:57
  • 2
    Макрос B8 работает путем преобразования "двоичного" буквально в шестнадцатеричный литерал и извлекать каждый четвертый бит. – dan04 10 April 2010 в 02:04
  • 3
    Интересно, что означает 0x ## n ## LU? Никогда не встречал такой синтаксис. – Federico A. Ramponi 10 April 2010 в 02:07
  • 4
    @hamza: это действительно довольно сложно. Но то, что вам нужно понять, это просто из # include & lt; stdio & gt; и далее. – Federico A. Ramponi 10 April 2010 в 02:10
  • 5
    @Federico: Оператор препроцессора ## соединяет маркеры вместе. Итак, в этом случае, если вы вызываете HEX__(10), он расширяется до 0x10LU. – James McNellis 10 April 2010 в 02:13

Вы можете попробовать:

bool i[8] = {0,0,1,1,0,1,0,1}
-8
ответ дан Francesco Menzani 19 August 2018 в 01:50
поделиться

Я продлил хороший ответ, заданный @ renato-chandelier, обеспечив поддержку:

  • _NIBBLE_(…) - 4 бит, 1 nibble в качестве аргумента
  • _BYTE_(…) - 8 бит, 2 глыбы в качестве аргументов
  • _SLAB_(…) - 12 бит, 3 глыбы в качестве аргументов
  • _WORD_(…) - 16 бит, 4 куска в качестве аргументов
  • _QUINTIBBLE_(…) - 20 бит, 5 глаголов в качестве аргументов
  • _DSLAB_(…) - 24 бит, 6 кусков в качестве аргументов
  • _SEPTIBBLE_(…) - 28 бит, 7 грызков в качестве аргументов
  • _DWORD_(…) - 32 бит, 8 глаголов в качестве аргументов

На самом деле я не очень уверен в терминах «quintibble» и «septibble». Если кто-нибудь знает какую-либо альтернативу, пожалуйста, дайте мне знать.

Вот макрос, переписанный:

#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))

И вот пример использования Ренато:

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; */
1
ответ дан madmurphy 19 August 2018 в 01:50
поделиться

C не имеет записи native для чистых двоичных чисел. Ваша лучшая ставка здесь будет либо восьмеричной (например, 07777) шестнадцатеричной (например, 0xfff).

12
ответ дан Nikolai Fetissov 19 August 2018 в 01:50
поделиться

C ++ предоставляет стандартный шаблон с именем bitset. Попробуйте, если хотите.

229
ответ дан Peter Mortensen 19 August 2018 в 01:50
поделиться
  • 1
    Несколько других компиляторов имеют тот или иной аналогичный способ выражения чисел в базе 2. – nategoose 12 April 2010 в 22:20
  • 2
    Было бы неплохо иметь это стандартизованное, но clang поддерживает одну и ту же нотацию. – polemon 11 April 2011 в 13:37
  • 3
    Он работает в Clang, GCC и TCC. Он не работает в PCC. У меня нет другого компилятора для тестирования. – Michas 20 June 2011 в 17:05
  • 4
    Я видел несколько встроенных системных компиляторов, которые его поддерживают. Я не знаю какой-либо особой причины, это не должно быть стандартной функцией языка. – supercat 1 August 2011 в 22:34
  • 5
  • 6
    Почему, например, B_0100 не используется (вместо 0100)? Как показано, например, char b = BYTE(0100,0001);. – Peter Mortensen 29 March 2017 в 16:09
  • 7
    @PeterMortensen B_ добавляется функцией препроцессора _B2H. – mxmlnkn 26 October 2017 в 17:02

Вы также можете использовать встроенную сборку следующим образом:

int i;

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

std::cout << i;

Хорошо, это может быть несколько перебор, но работает:)

2
ответ дан renger 19 August 2018 в 01:50
поделиться
  • 1
    Ваше решение не является многоплатформенным. Во многих архитектурах вы не можете включить ассемблерный код в C. В частности, в компиляторе Microsoft Visual Studio вы можете (при компиляции для x86 32bits). Но как вы даже знаете, зарегистрирован ли у вашего процессора регистр «eax»? Подумайте о процессорах ARM в мобильных телефонах, процессоре x64 и т. Д. У них нет «eax». Процессор MIPS даже не имеет команды 'mov' – DanielHsH 21 September 2015 в 17:51

«Тип» двоичного числа совпадает с любым десятичным, шестнадцатеричным или восьмеричным числом: int (или даже char, short, long long).

Когда вы назначаете константу, вы не можете назначить его 11011011 (любопытно и, к сожалению), но вы можете использовать hex. Hex немного легче мысленно перевести. Chunk in nibbles (4 бит) и перевести на символ в [0-9a-f].

2
ответ дан Stephen 19 August 2018 в 01:50
поделиться

На основании некоторых других ответов, но этот будет отклонять программы с незаконными бинарными литералами. Ведущие нули являются необязательными.

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

Пример:

#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;
}
4
ответ дан Thomas Eding 19 August 2018 в 01:50
поделиться
  • 1
    +1 Есть некоторые недостатки, но в целом это хорошее решение. Интересная часть для меня заключается в том, что она не может отвергать не только то, что явно недействительно (например, B(/2)), либо разумно, но не двоично (например, B(+2)), но также B(-001000000000000000000000) (когда unsigned long long равно 64 -бит), даже если все остальные отрицательные двоичные числа отклоняются. Кроме того, он равен B(001000000000000000000000), а не -B(001000000000000000000000), и могут быть определены большие двоичные числа, такие как -B(001111111111111111111111). – jerry 20 May 2013 в 21:13
  • 2
    @jerry: Спасибо, что указали на эти недостатки. Я обновил код, чтобы решить хотя бы некоторые из этих проблем. Недостаток, который все еще существует, - это что-то вроде этого B(1+0). Я не уверен, как с этим бороться, и я не уверен, что C ++ справится с этим. В любом случае, я считаю, что сейчас нужно попытаться сделать что-то немое. – Thomas Eding 20 May 2013 в 22:07
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';

Самая левая цифра литерала все равно должна быть 1, но тем не менее.

74
ответ дан wilhelmtell 19 August 2018 в 01:50
поделиться
236
ответ дан Peter Mortensen 30 October 2018 в 13:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: