《Beginning C++17》-学习笔记-Chapter 03-Working with Fundamental Data Types

The XOR operator is used less frequently than the & and | operators. Important applications arise, however, in for instance cryptography, random number generation, and computer graphics. XOR is also used for the backup of hard disk data by certain RAID technologies. Suppose you have three similar hard drives, two with data and one to serve as backup. The basic idea is to ensure that the third drive at all times contains the XOR’ed bits of all contents of the two other drives, like so:
Drive one ... 1010 0111 0110 0011 ...
Drive two ... 0110 1100 0010 1000 ...
XOR drive (backup) ... 1100 1011 0100 1011 ...

//不借助第三个变量,利用exclusive or运算,交换两个变量的值
//给两个int变量赋值,交换这两个int变量的数值后输出这两个int变量的值;可用3, 14 两个整数验证
#include <iostream>

int main()
{
	int first{}, second{};
	std::cout << "Enter two integers separated by a space: ";
	std::cin >> first >> second;

	first ^= second;
	second ^= first;
	first ^= second;
	std::cout << "In reverse order they are " << first << " and " << second << std::endl;
}

#include <iostream>

int main()
{
	std::cout << sizeof(unsigned short) << std::endl;//输出2,说明unsigned short占2个byte, 即16 bit;
	std::cout << (0b0000000000000001 << 2) << std::endl;//输出结果为4,即0b0000000000000100
	std::cout << (0b0000000000000001 | 0b0000000000000010) << std::endl;//输出结果为3,即0b0000000000000011
	std::cout << ~(~0b0000000000000001);//数值不变,输出结果仍为1,即0b0000000000000001
}
/*It will be convenient to display the data as hexadecimal values, and inserting std::hex in the output
stream does this. The hex is modal, so all subsequent integer output will be in hexadecimal format. It will be
easier to compare output values if they have the same number of digits and leading zeros. You can arrange
for this by setting the fill character as 0 using the std::setfill() manipulator and ensuring the field width
for each output value is the number of hexadecimal digits, which is 8(其中一项的设为了16,以示区别). The setfill() manipulator is modal,
so it remains in effect until you reset it. The std::setw() manipulator is not modal; you have to insert it into
the stream before each output value.*/
#include <iostream>
#include <iomanip>

int main()
{

	std::cout << std::hex                     // Hexadecimal output
		<< std::setfill('0');           // Fill character 0

	unsigned int flags{ 0xFF };                // Flags variable
	unsigned int bit1mask{ 0x1 };              // Selects bit 1
	unsigned int bit6mask{ 0b100000 };         // Selects bit 6
	unsigned int bit20mask{ 1u << 19 };        // Selects bit 20

	std::cout << "Use masks to select or set a particular flag bit:";
	std::cout << "\nSelect bit 1 from flags  : " << std::setw(16) << (flags & bit1mask);
	std::cout << "\nSelect bit 6 from flags  : " << std::setw(8) << (flags & bit6mask);
	std::cout << "\nSwitch off bit 6 in flags: " << std::setw(8) << (flags &= ~bit6mask);
	std::cout << "\nSwitch on bit 20 in flags: " << std::setw(8) << (flags |= bit20mask)/*The parentheses around the expressions are necessary here because the precedence of << is higher than
& and |.*/
		<< std::endl;
}

 输出结果:


#include <iostream>
#include <iomanip>

int main()
{
	enum class Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };/*When you define an enumeration, you’re creating a new type, so it’s also referred to as an enumerated data type.This defines an enumerated data type called Day, and variables of this type can only have values from the set that appears between the braces. The symbolic names between the braces are called enumerators.*/
	Day yesterday{ Day::Monday };/*You use type Day just like any of the fundamental types. When you reference an enumerator, it must be qualified by the type name.*/
	const Day poets_day{ Day::Friday };


	enum class Punctuation : char { Comma = ',', Exclamation = '!', Question = '?' };/*The type specification for the enumerators goes after the enumeration type name and is separated from it by a colon. */
	Punctuation ch{ Punctuation::Comma };

	std::cout << "yesterday's value is " << static_cast<int>(yesterday) /*To output the value of today, you must cast it to a numeric type because the standard output stream will not recognize the type Day*/
		<< static_cast<char>(ch) << " but poets_day's is " << static_cast<int>(poets_day)
		<< static_cast<char>(Punctuation::Exclamation) << std::endl;

}
#include <iostream>

int main()
{
	using my_type_new = unsigned long long; /* The using keyword enables you to specify a type alias, which is your own data type name that serves as an alternative to an existing type name.*/

	typedef short int my_type_old;/*older syntax for defining an alias for a type name。在以前的代码中存在,不建议继续使用*/

	my_type_new new_type_val{ 1034 };
	my_type_old old_type_val{ 231 };

	std::cout << new_type_val << std::endl;
	std::cout << old_type_val << std::endl;

}

All variables have a finite lifetime. They come into existence from the point at which you define them, and at some point they are destroyed—at the latest, when your program ends. How long a particular variable lasts is determined by its storage duration. There are four different kinds of storage duration:

  1. Variables defined within a block that are not defined to be static have automatic storage duration. They exist from the point at which they are defined until the end of the block, which is the closing curly brace of the block that encloses its
    definition , }.
    They are referred to as automatic variables or local variables. Automatic variables are said to have local scope or block scope.
  2. Variables defined using the static keyword have static storage duration. They are called static variables. Static variables exist from the point at which they are defined and continue in existence until the program ends.
     
  3. Variables for which you allocate memory at runtime have dynamic storage duration. They exist from the point at which you create them until you release their memory to destroy them.
     
  4. Variables declared with the thread_local keyword have thread storage duration.

Another property that variables have is scope. The scope of a variable is the part of a program in which the variable name is valid. Within a variable’s scope, you can refer to it, set its value, or use it in an expression. Outside of its scope, you can’t refer to its name. Any attempt to do so will result in a compiler error message.

The lifetime and scope of a variable are different things. Lifetime is the period of execution time over which a variable survives. Scope is the region of program code over which the variable name can be used.



 You can define variables outside all of the functions in a program. Variables defined outside of all blocks and classes are also called globals and have global scope (which is also called global namespace scope).

Global variables have static storage duration by default, so they exist from the start of the program until execution of the program ends. If you don’t initialize a global variable, it will be zero-initialized by default. This is unlike automatic variables, which contain garbage values when uninitialized.

Only global variables have default initial values, which is 0, not automatic variables.

Global variables have a scope that extends from the point at which they’re defined to the end of the file.

Variables with global scope are accessible from anywhere within the program file that contains them, following the point at which they’re defined, except where a local variable exists with the same name as the global variable. Even then, they can still be reached by using the scope resolution operator (::).

#include <iostream> 

long count1{ 999L };         // Global count1

int count3;                // Global count3 - default intialization, = 0

int main()
{ 
	int count1{ 10 };          // local count1, hides global count1
	std::cout << "Value of outer count1 = " << count1 << std::endl;
	std::cout << "Value of global count1 = " << ::count1 << std::endl;//you must use the scope resolution operator :: to access the global count1 in the output statement
	std::cout <<"Value of outer count3 = " << count3 << std::endl;//

} 

// Exercise 3-1. Output integer and its 1's complement in decimal and hexadecimal.

// The setw() manipulator only applies to the next output value so you must use it preceding each output value. 
// std::internal causes the fill character, '0', to be used internal to the hexadecimal values.
// Because the program computes the complement of signed integers, 
// the output of this program is strictly speaking undefined.
// That is: it depends on which binary representation of negative integers your computer uses.
// Nearly all computers employ the two's complement encoding though,
// which means that flipping all bits and adding one should negate your number.

#include <iostream>
#include <iomanip>

int main()
{
	int value{};
	std::cout << "Enter any integer: ";
	std::cin >> value;
	int inverted_value{ ~value };

	unsigned int hex_digits{ 2 * sizeof(int) };          /*Hex digits in value;每个int类型的数值占4 bytes, 32 bits, 每个16进制的数字可以代表4个bit,所以, 1个32位的int类型数值可以用8个16进制数字表示*/
	unsigned int hex_value_width{ hex_digits + 2 };      // Add 2 for 0x prefix
	unsigned int column_width{ hex_value_width + 4 };    // Output column width (add 4 for padding)

	// Output column headings
	std::cout << std::right << std::setw(column_width) << "value"
		<< std::setw(column_width) << "~value"
		<< std::setw(column_width) << "~value+1" << std::endl;

	// Output hexadecimal values
	std::cout << std::hex << std::showbase << std::internal << std::setfill('0')
		<< "    " << std::setw(hex_value_width) << value
		<< "    " << std::setw(hex_value_width) << inverted_value
		<< "    " << std::setw(hex_value_width) << inverted_value + 1 << std::endl;

	// Output decimal values
	std::cout << std::dec << std::right << std::setfill(' ')
		<< std::setw(column_width) << value
		<< std::setw(column_width) << inverted_value
		<< std::setw(column_width) << inverted_value + 1 << std::endl;
}
// casting from double to long (using static_cast<>()) ensures that the fractional part of the double value is omitted.

#include <iostream>

int main()
{

	double double_num_1{ 12.345 };
	double double_num_2{ 12.567 };

	std::cout<< static_cast<long>(double_num_1) << std::endl;//输出12
	std::cout << static_cast<long>(double_num_2) << std::endl;//输出12

}

#include <iostream>

int main()
{

	auto j { ~(~0u << 3) };/*~0 is composed of all 1s; shifting that three places to the left and complementing the result will leave 111, which is 7*/

	std::cout << j << std::endl;//输出7
}
// This program will only work if a single byte is 8 bit (virtually always the case),
// and the fundamental type int counts at least 4 bytes (true for most modern systems).

#include <iostream>
#include <iomanip>

int main()
{
	unsigned int two_char_word{};
	unsigned char ch{};//用来临时存贮字符

	//输入两个字符,存到two_char_word
	std::cout << std::left << std::setw(26) << "Enter a character: ";
	std::cin >> ch;
	two_char_word |= ch;

	std::cout << std::setw(26) << "Enter a second character: ";
	std::cin >> ch;
	two_char_word <<= 8;                                // Shift left 1 byte
	two_char_word |= ch;

	std::cout << "The hexadecimal number of the word containing 2 characters is " << std::right
		<< std::hex << std::showbase << std::internal << std::setfill('0') << two_char_word << std::endl;

	std::cout << std::setfill(' ');

	// 将刚才的两个字符倒序输出
	unsigned int mask{ 0x000000FF };              // Keep low order byte
	ch = mask & two_char_word;                          // Low order byte
	std::cout << std::setw(4) << ch;
	ch = mask & (two_char_word >> 8);                   // 2nd byte
	std::cout << std::setw(4) << ch;

}

#include <iostream>
#include <iomanip>

int main()
{
	const unsigned R{ 0x00FF0000 };
	const unsigned G{ 0x0000FF00 };
	const unsigned B{ 0x000000FF };
	enum class Color : unsigned
	{
		Red = R,
		Green = G,
		Blue = B,
		Black = 0,
		White = R | G | B,
		Yellow = R | G,
		Purple = R | B,
	};

	const Color color1{ Color::Yellow };

	auto color{ static_cast<unsigned>(color1) };  // Get the enumerator value,这一步将color1的类型由Color转换成auto类型,然后进行下面的&运算
	
	std::cout << std::setw(38) << "The components of color1 (yellow) are:"
		<< "  Red:" << std::setw(3) << ((color & R) >> 16) //不能直接用color1 和 R做 & 运算,因为类型不一致,编译时会报错
		<< "  Green:" << std::setw(3) << ((color & G) >> 8)
		<< "  Blue:" << std::setw(3) << (color & B) << std::endl;

}

猜你喜欢

转载自blog.csdn.net/CodingIsFun/article/details/83788150
今日推荐