+ 30
[BLOG] C++ Bread && Butter (Part 2/1)
+------------------+ Part 2/1: Data types 2-1: Integral types 2-2: Compound(composite) types 2-3: smallest kid in Integral family! 2-4: Subtle trinity! Coffee break: volatile qualifier +------------------+ Dear friends, Please send your comments, questions, suggestions, feedbacks, and criticisms to [https://www.sololearn.com/Discuss/683525/c-bread-butter-q-a] Many thanks for your understanding. ;)
11 ответов
+ 22
$ Tell me about "overflow" and "wrap-around", please!
An integer overflow occurs when you increase a signed integer beyond its maximum value or decrease beyond its minimum value.(Decreasing an integer beyond its minimum value is often referred to as an "integer underflow", although technically this term refers to a floating point condition.)
An integer "Wrap-around" means that if you increase the largest possible "unsigned integer" value, it continues from the smallest possible integer value. As opposite, if you decrease the smallest possible "unsigned integer" value, it continues from the largest possible integer value.
• Signed and unsigned char ranges:
- OK
! cause wrap-around/overflow
-128<------|------>127!!!!!!!>255
-128<!!!!!!0|---------------->255
0000 0000
^ \_______/
| magnitude
|
sign bit
0000 0000
\________/
magnitude
"ch2" is a signed char (-128 to 127). 200, is an "overflow" so, it gives you -56 by using
2's complement operation.
0 1100 1000 = 200
^ \________/
| magnitude
|
sign bit (expected to be the 8th bit, not 9th. Definitely an overflow!)
1 0011 0111 ---> 1's complement
0 0000 0001 +
-----------------
1 0011 1000 = -56
or simply 200 - (+numeric_limits<unsigned char>::max() + 1) = -56
"ch6" is an unsigned one (0 to 255). -1, is out of the bound so, it has "wrap-around" to 255 by
2's complement.
1 0000 0001 = -1
0 1111 1110
0 0000 0001 +
---------------
0 1111 1111 = 255
(+numeric_limits<unsigned char>::max() + 1) - 1 = 255
1 0000 0000 = 256
0 1111 1111
0 0000 0001 +
----------------
1 0000 0000 = 0
10 0000 0000 = 512
01 1111 1111
00 0000 0001 +
-----------------
10 0000 0000 = 0
Excuse me, Guru!
$ What would you suggest when somebody wants to use these triplets correctly?
Use "signed char" when you want a "one-byte signed numeric type", and use "unsigned char" when you want a "one-byte unsigned numeric type". Use "plain old char" when you want to "hold characters".
+ 21
But, if the compiler doesn't optimize it, then it has to fetch the value of flagX and compare it with 30, each time which obviously is a little bit slow. (That's cool, but I couldn't see the point!)
• However, sometimes, optimization may be undesirable. In our case, maybe someone (or something!) is changing the value of flagX from outside the program which compiler isn't aware of, since it can't see it; but it's how you've designed it. In that situation, compiler's optimization would not produce the desired result. (Did you get it?!)
Let me guess! volatile can help me to slap behind the compiler's head, right?!!!
Ugh...Jeez!
To ensure the desired result, you need to somehow stop the compiler from optimizing (messing around!) the while loop. That is where the volatile keyword plays it's role. [i.e. volatile int flagX = 30;]
volatile tells the compiler that:
"Hey compiler, I'm volatile and, you know, I can be changed by some XXX that you're not even aware of. That XXX could be anything. Maybe some alien outside this planet. Maybe some form of interrupt etc. You never know who is going to change me! So, stop playing an all-knowing god, and don't dare touch the code where I'm present. Okay?!"
>> 100% tip: Another well-known circumstance in which you might use volatile is when you are going to write some inline assembly code (Hardcore programming!).
AT&T inline ASM Format:
asm [volatile] ( assembler template
: output operands (optional)
: input operands (optional)
: list of clobbered registers (optional)
);
+----------------------+
Take a deep breath....!
+----------------------+
+ 20
$ I'm wondering why the bool type is 8 bits long (1 Byte), where only "one bit" is enough to hold the boolean value.
Because every C++ data type must be addressable. How would you create a pointer to a single bit? You can't. But you can create a pointer to a byte. So a boolean in C++ is typically byte-sized.
>> 100% note: No C++ datatype can be smaller than a byte.
********************
2-4: Subtle trinity!
********************
"Programming spirituality", said Guru.
"WHY?", asked student!
"To reveal the real truth of your crafts", responded Guru.
"HOW?", asked student!
"By shedding light on the darkest side of them", responded Guru.
"where can I find a torch?", asked student!!!
• Quick review:
char is an integer type, same as int, short and other integer types. Usually, char has the same length as bool which makes them the smallest types. Just like any other integer type, char can be signed or unsigned.
https://code.sololearn.com/ce6RZ3Kv0ior
Hey! What are those plus signs before numeric_limits templates?
They are MAGIC PLUS! (I'm +18!)
>> 120% tip: By putting a unary + operator behind built-in numeric types, those types promote and printable as a number, regardless of their type.(No more typecasting!)
• What's the subtlety?
Unlike the other integer types, there are "three distinct" basic character types: "char", "signed char", and "unsigned char". In particular, char is NOT the same type as signed char. Although there are three character types, there are only two representations: "signed and unsigned". The (plain) char type uses one of these representations. Which of the other two character representations is equivalent to char "depends on the compiler".
////////
char ch1 = 'x';
char ch2 = 200; // Overflow to -56
char ch3 = -130; // Underflow to 126
signed char ch4 = -110;
unsigned char ch5 = 256; // wrap-around to 0
unsigned char ch6 = -1; // wrap-around to 255
///////
https://code.sololearn.com/cbl46dKPD1mN
+ 19
*************************************
2-3: smallest kid in Integral family!
*************************************
What the heck are you doing bool?!
Nothing daddy! just playing with true and false!
• Quick review:
C++ provides the data type "bool" for variables that can hold only one of two states,"true" or "false". In general, the size of a bool type is 1 Byte. (Don't take my word for it and always use the "sizeof()" operator for getting the correct size--it's implementation dependent)
>> 5% pitfall: bool type can't be signed or unsigned.
unsigned bool b1 = true; // Syntax error
signed bool b2 = false; // Syntax error
>> 10% tip: Because bool type is an integral type you can assign a whole number (either positive
or negative) or even character constants to bool variables.
bool b1 = 47; // true
bool b2 = -106; // true
bool b3 = 0; // false
bool b4 = 'B'; // 66 = true
cout << b1 << b2 << b3 << b4; // output: 1101
See, only 0 yields false and in other cases the result will be true. By the same reason, the following
if statement is evaluated to true.
if (b4)
cout << "Done.";
>> 100% tip: If you'd like to see the result of a boolean variable or operation, as true and false
rather than 1 and 0, use the "boolalpha" stream manipulator(flag).
cout << boolalpha;
>> 100% pitfall: Don't forget to change the flag to "noboolalpha" once you change your mind about
the boolean stuff outputs.
cout << noboolalpha;
https://code.sololearn.com/ctyN1ZJONzQE
• Practical usage:
Have you ever think about the user input evaluation? Sure you have! In fact, one of the opportunities that you can take advantage of bool's power is in this example.
https://code.sololearn.com/cZ9N8nzrXXJC
• Bool arithmetic info:
"numeric_limits" template class describes arithmetic properties of built-in numerical types.
https://code.sololearn.com/c6VIQPKCJE4d
Wait...wait..wait!
What is it?!
+ 19
********************************
Coffee break: volatile qualifier
********************************
• Qualifier:
A qualifier adds an extra "quality"to an identifier. They're similar to adjectives:"A tipsy programmer", "An Attractive lady" and so forth. "const" and "volatile" are the only type qualifiers in C++ (Also known as cv-qualifer).
• volatile:
To support low-level programming, C++ defines some features that are inherently "nonportable". A nonportable feature is one that is "machine specific". Programs that deal directly with hardware often have data elements whose value is controlled by processes outside the direct control of the program itself. For example, a program might contain a variable updated by the system clock. An object should be declared volatile when its value might be changed in ways outside the control or detection of the program. The "volatile" keyword is a directive to the "compiler" that it should not perform optimizations on such objects.
(Let me show you a stupid example real quick to see the point!)
////////////
int main() {
int flagX = 30;
while (flagX == 30) {
// This block hasn't any
// obvious mechanism to change
// flagX state.(maybe there's
// just a "break" to avoid
// infinite loop)
// However, there's an XXX block
// of code refers to outside of this
// program that might affect on
// flagX value but compiler isn't
// aware of.
}
}
////////////
When this program gets compiled, the compiler may optimize this code, if it finds that the program "never ever" makes any attempt to change the value of flagX, so it may be tempted to optimize the while loop by changing it from "while (flagX == 30)" to simply "while (true)" so that the execution could be fast (since the condition in while loop always appears to be true).
+ 18
*******************
2-1: Integral types
*******************
Integral? Do you mean the mathematical integral?!
Ugh...! What a dumb question!
• Integral data types are those that represent only whole numbers.
$ So, How many Integral types exist in C++? (Who knows!)
Well, there's an adventurous and useful way to figure that out. Using C++11's type trait template
called "std::is_integral" along with its member constant "value", it will help you a great deal. Just remember, You must include "type_traits" header file to your program.
https://code.sololearn.com/cVHf3FNy7zhG
Awesome! So it returns a boolean value. If type T was an integral type it returns 1, otherwise 0,
right?
Absolutely right.
One more thing! What are those weird integer-like and char-like types plus "cstdint" header files?
Don't rush baby!
First of all, you need to know about "Type Alias", then gang of two, "typedef" and "using"!
• Type alias:
Type alias is a name that is a synonym for another type. Type aliases let you simplify complicated type definitions and making those types easier to use. Type aliases also let you emphasize the purpose for which a type is used.
1. Traditionally, you use a "typedef" to define a type alias.
Format: typedef existing_type new_type_name;
https://code.sololearn.com/cD6v0HW85W8J
2. The C++11 standard introduced a second way to define a type alias, via an "alias declaration":
Format: using new_type_name = existing_type;
https://code.sololearn.com/civJ5az25x7m
$ So, what's the difference between these two guys?
The only difference is that "typedef" has certain limitations in the realm of templates that "using" has not. Therefore, "using" is more generic, although typedef has a longer history and is probably more common in existing codes.
Now, I guess you are feeling at gut-level that what those weird Integral types were. But let me clarify
them a little more.
+ 17
• cstdint header file:
This header Provides typedefs for "fixed-width" integral types along with macros specifying their limits.
[e.g. some of those fixed-width declarations
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;]
What is a macro then?!
Simply, An identifier that stands for some set of code. In later parts you are going to see what
they are and how they work in details.(Promises are going to be fulfil by dear GURU!)
$ I can't understand! What's the point of using these kinds of "fixed-width" data types?
For the most part, to make your code more portable. But let me give you an example. Suppose you happened to write a program for a 36-bit architecture rather than a ubiquitous X86 (32-bit). This particular system supports integral data types with unusual bit sizes (width).
Type 32-bit 36-bit
char 8 b 9 b
short 16 b 18 b
int 32 b 36 b
long 64 b 72 b
Now, the question is "which kind of data types will be the most optimal and satisfactory for such a system that you are intending to write a program for"? (Oh Gosh, How should I know?!)
Let me pick "char" type for explaining.
In general, the width of a regular signed char in a 32-bit system, is 1 Byte (8 bits).
But as you see, there's no way to satisfy this constraint by a signed char type in 36-bit guy.
(Same limitation goes with "int8_t" type)
On the other hand, short int type is 2 Bytes (16 bits), and obviously it's not an optimal choice
in this case. So, let's think about "int_least8_t" and "int_fast8_t" for a moment...
Clock's ticking ...10 minutes...1 hour...!
Alright baby, stop thinking!
+ 17
If you don’t need a specific storage size (e.g 1 Byte, 2 Bytes etc), but want the smallest data structure with "at least" N bits, (N is 8 in our case) you most certainly use "int_leastN_t". Also, If you want the data structure that allows the "fastest access while having at least N bits" you would use "int_fastN_t".
>> 50% tip: (Fundamental types - Integral types) = {float, double, long double, void, nullptr_t} =
non integral types
https://code.sololearn.com/c5J2250zdJ5Q
******************************
2-2: Compound(composite) types
******************************
Hmmm...Seems like anything but programming! Is this one related to chemistry?!
Hmmm...Seems you need a Gibbs slap, Hah?!!!
A compound type is one that is defined in terms of another type. such as pointer, reference, array, function, function pointer, member object pointer, member function pointer, class, union, or enumeration. The same pasibility exist for checking whether a type is compound or not.
https://code.sololearn.com/cmvvfwx1Swo2
Let's fool around with "class" and "2 OLD friends" a little bit to settle our nerves!
https://code.sololearn.com/che7KS6dLAOl
+ 10
Something about bool..
hope it helps.
Bool is 8 bit because memory is managed in bytes.
a memory address refers to a byte.
so 7 bits are wasted, but don't worry, the operation on a bool is very fast and memory waste in this case is not a problem today.
However if you want to store huge amounts of bool data you can use bit stuff libraries etc.
but at runtime normal bool are best.
+ 10
Awesome job @Babak!
Very deep and well explained !
+ 4
thank you so much @babak sir