How can I confirm the range of unsigned long integer in C?
unsigned long has 8 bytes on my Linux gcc. unsigned long long has 8 bytes on my Linux gcc, too. So I think the range of integers they can show is from 0 min to (2^64 — 1)max. Now I want to confirm if I’m correct. Here is my code:
warning: integer constant is so large that it is unsigned
interstingly you test nothing with this code. You will ALWAYS get 0 independent of the size of the variable.
@KamiKaze With a 16-byte unsigned long long , printf(«%llu\n», b); will nicely print «18446744073709551616». ALWAYS is a long time, just wait a decade for 128-bit `unsigned long long.
5 Answers 5
When you initialize num, you can append the «UL» for unsigned long and ULL for unsigned long long .
unsigned long a = 18446744073709551615UL; unsigned long long b = 18446744073709551615ULL;
Also, use %zu instead of %d because sizeof return size_t .
- integer-suffix, if provided, may contain one or both of the following (if both are provided, they may appear in any order:
- unsigned-suffix (the character u or the character U )
- long-suffix (the character l or the character L ) or the long-long-suffix (the character sequence ll or the character sequence LL ) (since C99)
C standard 5.2.4.2.1 Sizes of integer types :
1 The values given below shall be replaced by constant expressions suitable for use in #if preprocessing directives. Moreover, except for CHAR_BIT and MB_LEN_MAX , the following shall be replaced by expressions that have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions. Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
You find some useful definitions in .
Initialize unsigned numbers with -1. This will automatically be MAX value in C.
Update: Changed the code based on comments 🙂
@KamiKaze This post does directly answer the title question: «How can I confirm the range of unsigned long integer in C?»
@chux The only thing mentioned and changed in this answer (in contrast to the question) is that (2^64 — 1) was replaced with -1. Then it adds 1 et voila the result is 0. This is does not tell us anything about the range of unsigned long.
How can I confirm the range of unsigned long integer in C?
Best, just use the macros from . It better self documents code’s intent.
unsigned long long b_max = ULLONG_MAX;
Alternatively, assign -1 to the unsigned type. As -1 is not in the range of an unsigned type, it will get converted to the target type by adding the MAX value of that type plus 1. The works even on rare machines that have padding.
. if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. C11dr §6.3.1.3 2
The min values is of course 0 for an unsigned type.
unsigned long long b_min = 0; unsigned long long b_max = -1; printf("unsigned long long range [%llu %llu]\n", b_min, b_max);
Note that picky compilers will complain about assigning an out-of-range value with b_max = -1; . Use ULLONG_MAX .
The warning «warning: integer constant is so large that it is unsigned» is due to 18446744073709551615 is a integer decimal constant outside the long long range on your platform. Unadorned decimal constants are limited to that. Append a U or u . Then the compiler will consider unsigned long long .
unsigned long long b = 18446744073709551615u;
Further, there is no C spec that says 18446744073709551615 is the max value of unsigned long long . It must be at least that. It could be larger. So assigning b = 18446744073709551615u may not assign the max value.
Изучение C++ в Linux. Типы данных.
С++ является типизированным языком программирования, где переменные, функции и их аргументы необходимо явно задавать. Так как язык является расширяемым, то типов данных может огромное множество, мы рассмотрим только основные.
В предыдущей статье, я коротко об этом упоминал, но давайте попробуем разобраться какие типы данных есть в языке C++:
Void
Типом void можно считать пустоту, то есть данный тип ничего не возвращает и не хранит. Данный тип нельзя использовать для объявления переменных. Как правило, данный тип используется для объявления функций, которые ничего не возвращают. Например:
#include using namespace std; void test() < cout int main()
Как видим из этого примера, у нас есть функция test(), которая имеет тип void. Единственное что делает данная функция, так это вывод текст на экран. Если вы попытаетесь сделать возвращение каких либо данных (return 0; return true; или return), то компилятор вернет ошибку. Но можно использовать следующую конструкцию:
#include using namespace std; void test()< int nNCelsius; cout > nNCelsius; if (nNCelsius > 10) < cout cout int main()
В данном примере, мы сделали возвращение пустого return; что бы завершить выполнение данной функции.
Целочисленные
Целочисленные типы хранят в себе, как понятно из названия, целые числа.
Char
Данный тип используется для хранения символов. Для Char отводиться в системе 1 байт (8 бит), что дает возможность закодировать 256 символов ASCII.
#include using namespace std; int main()
Вначале мы объявили переменную character с типом char, мы записали туда только одну букву, обратите внимание на кавычки, я использовал одинарные, это указывает системе, что тут один символ, если использовать двойные кавычки — будет ошибка. Если попытаться написать туда что-то еще, кроме буквы Z, то компилятор выдаст ошибку.
Вторая переменная charArr уже имеет [], что указывает, что я буду использовать строковой массив данных, и кавычки уже двойные. По сути текст: «Привет мир!» это массив из 11 символов.
По-этому если вам нужно использовать какой то текст, в котором больше чем 1 символ, вам нужно использовать строковой массив char charArr[] и двойные кавычки.
Bool
Тип данных Bool так же является целочисленным, но используется для логических операций, значение которое он может принимать от 0 до 255. 0 является значением false (ложь), а 1 и больше true (правдой)
#include using namespace std; bool CheckThis()< int nNCelsius; cout > nNCelsius; return (nNCelsius > 10); > int main() < bool Check = false; if ( Check )< cout else < cout if (CheckThis()) < cout else < cout return 0; >
Переменная Check — является типом bool, которой присвоено значение false (0 или ложь), дальше мы делаем довольно абсурдную конструкцию с точки программирования, но это сделано ради примера, так как код
Конструкцию return (nNCelsius > 10); можно представить так
Остальные целочисленные типы
Вместе с целочисленными типами можно использовать специальные модификаторы
- unsigned — значение будет идти без отрицательных чисел
- signed — значение может быть как положительным, так и отрицательным
short int
Целое число, небольшого диапазона, занимающая всего 2 байта в памяти. Short int может принимать значения от -32 768 до 32 767. Если добавить модификатор unsigned то значение будет от 0 до 65 535
#include #include using namespace std; int main()
Обратите внимание, что выдаст программа если превышено значение принимаемого значения? Да, будет -32768, мы получим самый крайний отрицательный результат, для данного типа. Тоже актуально и для остальных целочисленных типов!
Int
Целое число, для данного типа выделяется 4 байта памяти. Int имеет значения от -2 147 483 648 до 2 147 483 647. Если добавить unsigned, то значение будет от 0 до 4 294 967 295
#include #include using namespace std; int main()
long int
Данный тип занимает 8 байта и имеет значения от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807, а unsigned long int от 0 до 18 446 744 073 709 551 615
#include #include using namespace std; int main()
Типы с плавающей точкой или дробные типы
В С++ существует 2 типа, позволяющие записывать числа с плавающей точкой — float и double
Float
Данный тип занимает 4 байта, и может иметь значения от -2 147 483 648.0 до 2 147 483 647.0
#include #include using namespace std; int main()
Double
Данный тип занимает 8 байта, и может иметь значения от -9 223 372 036 854 775 808 .0 до 9 223 372 036 854 775 807.0
#include #include using namespace std; int main()
В C++ есть еще такой тип как перечисления (enum) его я рассмотрю в следующих статьях.
Long type 64bit linux
Very simple questions guys, but maybe I’m just forgetting something. In 64bit linux, a long is 8bytes correct? If that’s the case, and I want to set the 64th bit, I can do the following:
Whenever I compile this, however, it gives me an error saying that I’m left shifting by more than the width. Also, if I wanted to take the first 32bits of a long type (without sign extension), can I do:
Depends on which compiler is used. Many legacy compilers would default to 32-bit longs, even if running on a 64 bit machine. Confirm that sizeof num is 8 before trying anything more.
@cnicutar After you answer the same questions many times over and over again, it starts to get old. So I can’t get myself to do more than a 1 line answer.
5 Answers 5
In 64bit linux, a long is 8bytes correct?
Need not be. Depends on the compiler than on the underlying OS. Check this for a nice discussion. What decides the sizeof an integer?
Whenever I compile this, however, it gives me an error saying that I’m left shifting by more than the width
Everyone have already answered this. Use 1UL
Also, if I wanted to take the first 32bits of a long type (without sign extension), can I do:
num = num&0xFFFFFFFF; or what about: num = (int)(num);
num = num&0xFFFFFFFF . This will give you the lower 32-bits. But note that if long is just 4 bytes on your system then you are getting the entire number. Coming to the sign extension part, if you’ve used a long and not unsigned long then you cannot do away with the sign extended bits. For example, -1 is represented as all ones, right from the 0th bit. How will you avoid these ones by masking?
num = (int)(num) will give you the lower 32-bits but compiler might through a Overflow Exception warning if num does not fit into an int
Agree that C doesn’t impose long to be 64bits on 64bits machine. However linux implicitely imposes that. Just take a look at all the pointers passed through unsigned long and memory offsets passed through signed long (e.g. syscalls). Thus, as long as linux source code doesn’t drastically change, I would answer yes to the question : «In 64bit linux, a long is 8bytes, correct ?»
Actually, if you want some precise length (in bits) for your integers, assuming a C99 conforming compiler, #include and use types like int64_t , int32_t etc. A handy type is intptr_t , an integer type with the same number of bits as void* pointer (so you can call it a machine «word»)
A C99 conforming compiler does not need to provide fixed-width types, e.g. int64_t . Only twos-complement implementations that provide 8-, 16-, 32- and 64-bit integer types with no padding bits are required to provide fixed-width integer typedefs in stdint.h .
For portability you could use:
#define LNG_BIT (sizeof(long) * CHAR_BIT) unsigned long num = 1UL
To get "low int", something like?:
#define INT_BIT (sizeof(int) * CHAR_BIT) if (LNG_BIT > INT_BIT) return num & (~0UL >> INT_BIT); else return num;
Or, use mask, etc. Depends in large on why, for what, etc. you want the int bits.
Also notice the options given by compilers; I.e. if you are using gcc:
-m32
-m64
-mx32
Generate code for a 32-bit or 64-bit environment.
* The -m32 option sets int, long, and pointer types to 32 bits, and generates code that runs on any i386 system.
* The -m64 option sets int to 32 bits and long and pointer types to 64 bits, and generates code for the x86-64 architecture. For Darwin only the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options.
* The -mx32 option sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture.There is also -maddress-mode=long etc.
-maddress-mode=long
Generate code for long address mode. This is only supported for 64-bit and x32 environments. It is the default address mode for 64-bit environments.