Как записать шестнадцатеричное число в c
Перейти к содержимому

Как записать шестнадцатеричное число в c

  • автор:

4.13 – Литералы

В программировании константа – это фиксированное значение, которое нельзя изменять. В C++ есть два типа констант: литеральные константы и символьные константы. В этом уроке мы рассмотрим литеральные константы, а в следующем – символьные константы.

Литеральные константы (обычно называемые просто литералами) – это значения, вставленные непосредственно в код. Например:

Они являются константами, потому что их значения не могут быть изменены динамически (сначала вы должны изменить их, а затем перекомпилировать программу, чтобы изменение вступило в силу).

Так же, как у объектов есть тип, тип есть и у всех литералов. Тип литерала предполагается из значения и формата самого литерала.

Значение литерала Примеры Тип по умолчанию
целое число 5, 0, -3 int
логическое значение true , false bool
число с плавающей запятой 3.4, -2.2 double (не float )
символ ' a ' char
строка в стиле C " Hello, world! " const char[14]

Суффиксы литералов

Если тип литерала по умолчанию не соответствует необходимому, вы можете изменить тип литерала, добавив суффикс:

Тип данных Суффикс Назначение
int u или U unsigned int
int l или L long
int ul , uL , Ul , UL , lu , lU , Lu или LU unsigned long
int ll или LL long long
int ull , uLL , Ull , ULL , llu , llU , LLu или LLU unsigned long long
double f или F float
double l или L long double

Обычно вам не нужно использовать суффиксы для целочисленных типов, но вот пара примеров:

По умолчанию литеральные константы с плавающей точкой имеют тип double . Чтобы они были типа float , необходимо использовать суффикс f (или F ):

Начинающие программисты часто не понимают, почему следующий код работает не так, как ожидалось:

Поскольку у 4.1 нет суффикса, он рассматривается как литерал типа double , а не как литерал типа float . Когда C++ определяет тип литерала, ему всё равно, что вы делаете с литералом (например, в данном случае используете его для инициализации переменной float ). Следовательно, 4.1 необходимо преобразовать из double в float , прежде чем его можно будет присвоить переменной f , и это может привести к потере точности.

Литералы можно использовать в коде C++, если их значения понятны. Чаще всего это происходит при использовании для инициализации или присвоения значения переменной, выполнения математических операций или вывода текста на экран.

Строковые литералы

В уроке «4.11 – Символы» мы определили строку как набор последовательных символов. C++ поддерживает строковые литералы:

Строковые литералы в C++ по историческим причинам обрабатываются очень странно. На данный момент можно использовать строковые литералы для печати текста с помощью std::cout , но не пытайтесь назначать их переменным или передавать их функциям – это либо не сработает, либо будет работать не так, как вы ожидаете. О строках в стиле C (и о том, как обойти все эти странные проблемы) мы поговорим подробнее в будущих уроках.

Экспоненциальная запись для числовых литералов с плавающей запятой

Есть два разных способа объявить литералы с плавающей точкой:

Во второй форме число после экспоненты может быть отрицательным:

Литералы в восьмеричной и шестнадцатеричной системах счисления

В повседневной жизни мы считаем, используя числа в десятичной системе счисления, где каждая цифра может быть 0, 1, 2, 3, 4, 5, 6, 7, 8 или 9. Десятичная система счисления число также называется «с основанием 10», потому что в ней возможно использование 10 цифр (от 0 до 9). В этой системе мы считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,… По умолчанию, числа в программах на C++ считаются десятичными.

В двоичной системе счисления всего 2 цифры: 0 и 1, поэтому она называется «с основанием 2». В двоичном формате мы считаем так: 0, 1, 10, 11, 100, 101, 110, 111,…

Существуют две других системы счисления, которые иногда используются в вычислениях: восьмеричная и шестнадцатеричная.

Восьмеричная система счисления – с основанием 8, то есть доступны только цифры: 0, 1, 2, 3, 4, 5, 6 и 7. В восьмеричном формате мы считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12,… (примечание: цифр 8 и 9 нет, поэтому мы сразу переходим от 7 к 10).

Десятичная система 0 1 2 3 4 5 6 7 8 9 10 11
Восьмеричная система 0 1 2 3 4 5 6 7 10 11 12 13

Чтобы использовать литерал в восьмеричном формате, добавьте к вашему литералу префикс 0 (ноль):

Эта программа печатает:

Почему 10, а не 12? Потому что числа печатаются в десятичном формате, а 12 в восьмеричном формате = 10 десятичном формате.

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

Шестнадцатеричная система счисления — с основанием 16. В шестнадцатеричной системе мы считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12,…

Десятичная система 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Восьмеричная система 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11

Чтобы использовать литерал в шестнадцатеричном формате, добавьте к нему префикс 0x .

Эта программа печатает:

Поскольку для одной шестнадцатеричной цифры возможны 16 различных значений, мы можем сказать, что одна шестнадцатеричная цифра использует 4 бита. Следовательно, пара шестнадцатеричных цифр может использоваться для точного представления полного байта.

Рассмотрим 32-битное целое число со значением 0011 1010 0111 1111 1001 1000 0010 0110 . Из-за длины и повторяемости цифр его нелегко прочитать. В шестнадцатеричном формате это же значение будет выглядеть так: 3A7F 9826 . Это делает шестнадцатеричные значения полезными как краткий способ представления значения в памяти. По этой причине шестнадцатеричные значения часто используются для представления адресов или необработанных значений в памяти.

До C++14 не было возможности назначить литерал в двоичном формате. Однако шестнадцатеричные пары предоставляют нам для этого полезный обходной путь:

Литералы в двоичном формате и разделители цифр C++14

В C++14 мы можем назначать литералы в двоичном формате с помощью префикса 0b :

Поскольку длинные литералы трудночитаемы, в C++14 также добавлена ​​возможность использования кавычек ( ' ) в качестве разделителя цифр.

Если ваш компилятор несовместим с C++14, он пожалуется, если вы попытаетесь использовать любой из этих приемов.

Печать десятичных, восьмеричных, шестнадцатеричных и двоичных чисел

По умолчанию C++ выводит значения в десятичном формате. Однако вы можете указать ему, что необходимо печатать в других форматах. Печать в десятичном, восьмеричном или шестнадцатеричном формате упрощается благодаря использованию std::dec , std::oct и std::hex :

Эта программа печатает:

Печать в двоичном формате немного сложнее, поскольку std::cout не имеет для этого встроенной возможности. К счастью, стандартная библиотека C++ включает в себя тип std::bitset (в заголовке <bitset> ), который сделает это за нас. Чтобы использовать std::bitset , мы можем определить переменную std::bitset и указать std::bitset , сколько бит мы хотим сохранить. Количество бит должно быть константой времени компиляции. std::bitset может быть инициализирован целочисленным значением без знака (в любом формате, включая десятичный, восьмеричный, шестнадцатеричный или двоичный).

Эта программа напечатает:

Мы также можем создать временный (анонимный) std::bitset для печати одного значения. В приведенном выше коде эта строка:

создает временный объект std::bitset с 4 битами, инициализирует его с помощью литерала 0b1010 , печатает его значение в двоичном формате, а затем отбрасывает временный std::bitset .

Магические числа, и почему это плохо

Рассмотрим следующий фрагмент:

Число, такое как 30 в приведенном выше фрагменте, называется магическим числом. Магическое число – это литерал (обычно число) в середине кода, не имеющий никакого контекста. Что значит 30? Хотя вы, наверное, догадываетесь, что в данном случае это максимальное количество студентов в классе, но это не совсем очевидно. В более сложных программах может быть очень сложно сделать вывод, что представляет собой жестко запрограммированное число, если нет комментария, объясняющего его.

Использование магических чисел обычно считается плохой практикой, потому что, помимо отсутствия контекста, для чего они используются, они создают проблемы, если значение необходимо изменить. Предположим, школа покупает новые парты, позволяющие увеличить количество учеников в классе с 30 до 35, и наша программа должна это отразить. Рассмотрим следующую программу:

Чтобы обновить нашу программу для использования нового размера класса, нам нужно будет обновить константу с 30 до 35. Но как насчет вызова setMax() ? Имеет ли это число 30 то же значение, что и другое число 30? Если да, то его следует обновить. В противном случае его следует оставить в покое, иначе мы можем сломать нашу программу где-нибудь еще. Если вы выполняете глобальный поиск и замену, вы можете случайно обновить аргумент setMax() , хотя он не должен был изменяться. Таким образом, вам нужно просмотреть весь код для каждого экземпляра литерала 30, а затем определить, нужно ли его изменить или нет. Это может занять много времени (и привести к ошибкам).

Хотя мы говорим «магические числа», это относится ко всем видам значений. Рассмотрим следующий пример:

В этом примере только одно число (100), но оно также используется в строках. Если мы решим обновить максимальное количество, скажем, на 200, нам придется обновить три разных случая, где встречается 100.

К счастью, существуют лучшие варианты (символьные константы). Об этом мы поговорим на следующем уроке.

Преобразование целого числа в шестнадцатеричное в C#

В этом посте будет обсуждаться, как преобразовать целое число в шестнадцатеричное в C# и наоборот.

Преобразование целого числа в шестнадцатеричное в C#

1. Convert.ToString() метод

Рекомендуемый подход заключается в использовании встроенного метода Convert.ToString() для преобразования целочисленного значения со знаком в его эквивалентное шестнадцатеричное представление. Этот метод продемонстрирован ниже:

2. Int32.ToString() метод

The Int32.ToString() можно использовать для преобразования числового значения в эквивалентное строковое представление с использованием указанного формата. В следующем примере отображается Int32 значение с использованием спецификаторов стандартного числового формата для шестнадцатеричного (т.е. X или же x ).

Integer to hex string in C++

How do I convert an integer to a hex string in C++?

I can find some ways to do it, but they mostly seem targeted towards C. It doesn’t seem there’s a native way to do it in C++. It is a pretty simple problem though; I’ve got an int which I’d like to convert to a hex string for later printing.

27 Answers 27

Use <iomanip> ‘s std::hex . If you print, just send it to std::cout , if not, then use std::stringstream

You can prepend the first << with << «0x» or whatever you like if you wish.

Other manips of interest are std::oct (octal) and std::dec (back to decimal).

One problem you may encounter is the fact that this produces the exact amount of digits needed to represent it. You may use setfill and setw this to circumvent the problem:

So finally, I’d suggest such a function:

To make it lighter and faster I suggest to use direct filling of a string.

AndreyS Scherbakov's user avatar

You can do it with C++20 std::format :

Until std::format is widely available you can use the library, std::format is based on (godbolt):

Disclaimer: I’m the author of and C++20 std::format .

Use std::stringstream to convert integers into strings and its special manipulators to set the base. For example like that:

phlipsy's user avatar

Just print it as an hexadecimal number:

s4eed's user avatar

Since C++20, with std::format , you might do:

Jarod42's user avatar

You can try the following. It’s working.

Peter Mortensen's user avatar

Mahmut EFE's user avatar

Just have a look on my solution, [1] that I verbatim [2] copied from my project. My goal was to combine flexibility and safety within my actual needs: [3]

  • no 0x prefix added: caller may decide
  • automatic width deduction: less typing
  • explicit width control: widening for formatting, (lossless) shrinking to save space
  • capable for dealing with long long
  • restricted to integral types: avoid surprises by silent conversions
  • ease of understanding
  • no hard-coded limit

[1] based on the answer by Kornel Kisielewicz
[2] Only the German API doc was translated to English.
[3] Translated into the language of CppTest, this is how it reads:

This is a bit verbose since std::to_chars works with a pre-allocated buffer to avoid dynamic allocations, but this also lets you optimize the code since allocations get very expensive if this is in a hot spot.

For extra optimization, you can omit pre-initializing the buffer and check the return value of to_chars to check for errors and get the length of the data written. Note: to_chars does NOT write a null-terminator!

Violet Giraffe's user avatar

Thanks to Lincoln’s comment below, I’ve changed this answer.

The following answer properly handles 8-bit ints at compile time. It doees, however, require C++17. If you don’t have C++17, you’ll have to do something else (e.g. provide overloads of this function, one for uint8_t and one for int8_t, or use something besides «if constexpr», maybe enable_if).

Original answer that doesn’t handle 8-bit ints correctly as I thought it did:

Kornel Kisielewicz’s answer is great. But a slight addition helps catch cases where you’re calling this function with template arguments that don’t make sense (e.g. float) or that would result in messy compiler errors (e.g. user-defined type).

I’ve edited this to add a call to std::to_string because 8-bit integer types (e.g. std::uint8_t values passed) to std::stringstream are treated as char, which doesn’t give you the result you want. Passing such integers to std::to_string handles them correctly and doesn’t hurt things when using other, larger integer types. Of course you may possibly suffer a slight performance hit in these cases since the std::to_string call is unnecessary.

Note: I would have just added this in a comment to the original answer, but I don’t have the rep to comment.

I can see all the elaborate coding samples others have used as answers, but there is nothing wrong with simply having this in a C++ application:

C++ is effectively the original C language which has been extended, so anything in C is also perfectly valid C++.

Take a look at SO answer from iFreilicht and the required template header-file from here GIST!

januw a's user avatar

My solution. Only integral types are allowed.

Update. You can set optional prefix 0x in second parameter.

definition.h

main.cpp

Results:

output

ANOTHER SIMPLE APPROACH

For those of you who figured out that many/most of the ios::fmtflags don’t work with std::stringstream yet like the template idea that Kornel posted way back when, the following works and is relatively clean:

Code for your reference:

parasrish's user avatar

I would like to add an answer to enjoy the beauty of C ++ language. Its adaptability to work at high and low levels. Happy programming.

ORParga ORParga's user avatar

for fixed number of digits, for instance 2:

you can also write a for cycle variant to handle variable digits amount

  • speed: it is a minimal bit operation, without external function calls
  • memory: it use local string, no allocation out of function stack frame, no free of memory needed. Anyway if needed you can use a field or a global to make the value_ex to persists out of the stack frame

Luca C.'s user avatar

With the variable:

will result in selA containing the string SELA;0x55;

Note that the things surrounding the 55 are just particulars related to the serial protocol used in my application.

Using void pointer:

char_to_hex returns a string of two characters

All the answers I read are pretty slow, except one of them, but that one only works for little endian CPUs. Here’s a fast implementation that works on big and little endian CPUs.

Compared to std::format and fmt::format("<:x>", value) , I get between 2x (for values > (1ll << 60)) and 6x the speed (for smaller values).

Examples of input/output:

You can define MACRO to use as one liner like this.

Haseeb Mir's user avatar

This question is quite old but the answers given are to my opinion not the best. If you are using C++20 then you have the option to use std::format which is a very good solution. However if you are using C++11/14/17 or below you will not have this option.

Most other answers either use the std::stringstream or implement their own conversion modifying the underlying string buffer directly by themselves. The first option is rather heavy weight. The second option is inherently insecure and bug prone.

Since I had to implement an integer to hex string lately I chose to do a a true C++ safe implementation using function overloads and template partial specialization to let the compiler handle the type checks. The code uses sprintf (which one of its flavors is generally used by the standard library for std::to_string ). And it relies on template partial specialization to correctly select the right sprintf format and leading 0 addition. It separately and correctly handles different pointer sizes and unsigned long sizes for different OSs and architectures. (4/4/4, 4/4/8, 4/8/8)

Детский вопрос о работе с шеснадцатеричном представлении числа

Собственно вопрос заключается в том, что до меня не доходит как работать с шеснадцатиричным представлением числа в си.

Почему это не работает.

Вопрос 2: Как через argv передать шестнадцатиричное число??

> Почему это не работает.

А почему оно должно работать? Условие d==’\xff’ никогда не выполняется.

1. 16-ричные числа записываются как 0xABCD без кавычек
2. argv — массив ссылок на строки. соответственно использовать надо строковые функции, sscanf, например.

> Почему это не работает.

ты будешь шокирован, может даже застрелишься (надеюсь), но 1 ≠ 255… наука высших сфер, все дела, тебе не понять…

> Вопрос 2: Как через argv передать шестнадцатиричное число??

передай шестнадцатеричное значение.

1. Может я неправильно понял Керниигана. Там #define DDD ‘\xhh’ -где hh это произвольный шеснадцатиричный код. . именно в кавычках. 2. про scanf понял. и даже помню, но. Разве нельзя взять строку из argv и сделав с ней нехиттрые преобразования получить переменную типа int. C одиночным символом это сделать можно. s-‘0’ (опять-же Керниган) А если с двумя. Можно-ли разобрать строку из argv и записать в массив по одному элементу и так. далее..далее.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *