1. ホーム
  2. c

C言語のこの小さなディテールを知っていましたか?

2022-02-20 03:53:03
<パス

記事目次


タイトルに細かいとあるので。 一旦、詳細を説明すると なんて無意味なんだああ、最初のピットはそれから詳細を紹介すればいいんだ、ねえ。7問はわかりやすいから、何問正解できるか見てみよう。


計算の詳細

①:

#include 
What is the answer to this question? Don't look at the back of the answer yet!

The answer is -126, hey, did you get it wrong? Don't worry, keep reading the following questions ②:
#include 
What do you think the answer to this question is? Don't look at the answers that follow!

The answer is c, hey, is not another wrong answer, do not rush, and then look at the back of the question ③: #include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is 1 4 4, hey, is not another wrong answer, first do not worry, and then look at the back of the question
Expression details ①: #include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is 5 or 4, yes Not sure The answer is 5 or 4, it is not sure, hey, is it a wrong answer again, don't be anxious, look again after
The questions on the back
②: int main() { int i = 10; i = i-- - --i * ( i = -3 ) * i++ + ++i; printf("i = %d\n", i); return 0; } What do you think the answer to this question is? Don't look at the answers that follow!
There are many answers, and the results are different in different compilers, which means it's still cannot determine the result Hey, you still got the wrong answer, don't worry, just look at the rest of the question #include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is Different results for different compilers Hey, did you get it wrong again? Don't worry, let's look at the rest of the question
④: #include This is the last question, how many have you gotten right so far? Please try in the comments. Hey!
The answer to this question is Different results for different compilers
How many questions did everyone answer correctly? Feel free to comment! 1. Now formally explain all the above questions designed to the content of -------- expressions to find the value The order in which expressions are evaluated is partly determined by the precedence and union of operators.
Similarly, some expressions have operands that may need to be converted to other types during the evaluation process. 1.1 Implicit type conversion (integer truncation and lifting) What is implicit type conversion, integer boosting, and integer truncation? C's integer arithmetic operations are always at least to meet the precision of the integer type to be performed.
To obtain this precision, an expression that has char and short types must be converted to integers before they can be used, a process called Integer Boosting
.
The process by which a larger data type is stored in a smaller data type is called Integer Truncation , such as the integer a = 500 , but a puts his value in the Character type b b cannot fully store a, and the Integer truncation
.
And this conversion behavior is called implicit type conversion 1.1.1 Explanation of the first question #include We know that everything in a computer is the complement of an operation. So it's the same here, (if you don't understand the original code and the inverse code, go to Baidu).
The original code, inverse code, and complement of a positive number are exactly the same
...for negative numbers, the complement is the inverse plus one, and the inverse is the inverse of the original code with all bits except the sign bit.
a has only 1 byte, and its complement is 00000011 (binary)
The b has only 1 byte, and its complement is 01111111 (binary)
a plus b, which is an arithmetic operation, needs to be raised to 4 bytes. And there are two ways to boost an integer
Arithmetic Boosting: Completes the first sign digit up to 32 bits Logical boosting: just fill in the zeros no matter what, up to 32 bits
Most calculators do arithmetic boosting , which is explained here Arithmetic Boosting . aAfter arithmetic lifting is 000000000000000000000000000000000011
bAfter the arithmetic boost is 000000000000000000000000000001111111
The result of a+b is ------ 000000000000000000000000000010000010
The integer truncation occurs because c is only 1 byte, so only the last 8 bits are accessed.
10000010
At this point c is accessing complement, and c is signed, Remember!!! When you print the code, it will be restored to the original code, and the number corresponding to the complement is -126 Here is a sheet of character types Original code complement inverse code The corresponding understanding diagram for
So the signed range is [-128,127]
The unsigned range is [0,255] It's better to turn it into a circle and find it yourself by the symbols.

1.1.2 Explanation of the second question

#include 

The binary of 0xb6 is 000000000000000000000000000010110110
Save it in a, truncate it, and get 1011 0110
The binary of 0xb600 is 00000000 00000000 10110110 00000000
The truncation occurs in b, and we get 10110110 00000000
0xb6000000 10110110 00000000 00000000 00000000
Save it in c just right.

a is now stored in the complement, and a is compared to 0xb6, which is involved in the operation, so the integer is raised to
11111111 11111111 11111111 10110110 ,

  • The integer boosted number is not the same as the 0xb6 binary, so it is not equal.

b is stored as a complement, and b is compared to 0xb600, which is involved in the operation, so it is integer-boosted to
11111111 11111111 10110110 00000000

  • The integer boosted number is not the same as the 0xb600 binary, so it is not equal

c is stored at this point as 10110110 00000000 00000000 00000000 Note that some people may ask 0xb6000000 is a positive number, Not !!!!! , literal constants are the default int type as long as they don't have a sign. So at this point 0xb6000000 is more than int, it is considered to be the complement of a negative binary number. So c and 0xb6000000 is equivalent.



1.1.3 Explanation of the third question

#include 

sizeof Measures the value of the type attribute.
c The type of the char The answer is 1, because there is only one byte
+c , + It is a monomial operator, and with c, the integer is raised to int, so it is 4 bytes, and the answer is 4
-c , and by the same token, still 4

1.2 Arithmetic conversions

As we said above, if the operand size is smaller than int, integer boosting occurs, but what if all types larger than or equal to int are involved in arithmetic operations? Here's where we get into the Arithmetic conversion .
What is an arithmetic conversion? For example, the following example:

#include 

The result will print a will be greater than b
Because this is an arithmetic conversion, i.e. it still needs to satisfy the same type of operation, unsigned int is higher than int, so the value of a will default to unsigned, and a will be larger than b.

Arithmetic boosting direction:


1.3 Operator Attributes

There are three factors that influence the valuation of complex expressions.

  1. Operator precedence
  2. Combinability of operators
  3. Whether to control the order of evaluation.

1.3.1 What is priority?

It's deciding what to calculate first. For example d = a + b*c . Because * has a higher priority than + , so the b*c and then calculate +

1.3.2 What is bonding?

It is the decision of which direction to calculate from, given the same priority. For example d = a * b * c because the successive * , the precedence is no longer useful, so it's a combination at this point, * The union is from left to right. This means that the a*b and then calculate *c .

1.3.3 What is the order of evaluation?

There are only a few operators in c that have evaluation order, such as ||, && , !
That order of values What exactly does that mean?
For example, a equals 0, b equals 2, and c equals 3, d = a && b && c The value of d ends up being 0, but it only goes as far as a when the operation is done, because && is as long as you encounter false is false, after the true or false is no longer relevant, a is 0, is false, so do not care about the next. That's the order of the values.

Here are two small exercises on the order of values:

#include 

The answer is 1 2 3 4 . Reason: a is a post ++, the value of a=0 is used first, it is encountered false at the beginning, and is not executed later. But a is still added, because the post-plus is is used first and then added

#include 

Answer: 1 2 3 4 The first ++, i.e., the first plus, a becomes 1, because || ends as soon as it meets true, and doesn't care if it's true or false. So only a changes.


Here's a table of operator properties:


Where the priority decreases from top to bottom

1.3.4 The fourth question explains

#include 

ret = c + --c There are two operation symbols in Priority , -- has a higher priority than + , so it was decided to count -c first, but + When is the c to the left of the number prepared? As we know, c is a compiled language, so after the code is written, it needs to be compiled into machine language first and then executed. So at compile time, the value to the left of the + sign is in the --c before it is compiled, or --c was compiled afterwards? It's not certain.

  • Under the vs compiler the answer is 4, which is the same as the --c After preparing the c
  • Under the gcc compiler the answer is 5, which is in the --c before preparing the c

So: this is the problem code, let's not write such garbage code in the future.

1.3.5 Explanation of the fifth problem

int main()
{
	 int i = 10;
	 i = i-- - --i * ( i = -3 ) * i++ + ++i;
	 printf("i = %d\n", i);
	 return 0;
}

This is the same thing, although the priority is known, it is not certain when the operands in the union are ready, and you can see the result of the operation in different compilers:

Again, it's a garbage code

1.3.6 Explanation of the sixth problem

#include 

() The function call symbol has the highest priority, but there are three of them, so which one should be called first? Again, it's not clear.

  • The vs compiler calls them from left to right, resulting in -10.
  • But what about other compilers? Try gcc, codeblocks, Devc++, and you'll see that it's completely different.

1.3.7 Explanation of the seventh question

Before saying more about this question, the blogger must criticize some colleges, why? Schools teach people ++ The symbols are not the most like to use this type to test everyone? Here to tell you clearly, this is a complete waste of time!!!! Because this code is meaningless!!!! is garbage code

#include 

First, () The parentheses have the highest priority, but there are three of them, so which one should we count first?
Second, a i change, will it affect the other one? I'm not sure here. It's the same as in question 4, where we said that before compiling c exactly when to prepare the same. Not sure.!!!

  • The value of the vs compiler is 12 4
  • The value for the gcc compiler is 10 4
    Different values for different compilers, different results, such code does not deserve to be called code.!!!!

So, if you see this kind of question in the future, just skip it, it doesn't make sense.

Summary:

  • Knowing what integer lifting and truncation are
  • Knew what an arithmetic conversion was
  • Knowing the properties of what operators are used, you can't write crap like this in the future.
#include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is c, hey, is not another wrong answer, do not rush, and then look at the back of the question ③: #include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is 1 4 4, hey, is not another wrong answer, first do not worry, and then look at the back of the question
Expression details ①: #include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is 5 or 4, yes Not sure The answer is 5 or 4, it is not sure, hey, is it a wrong answer again, don't be anxious, look again after
The questions on the back
②: int main() { int i = 10; i = i-- - --i * ( i = -3 ) * i++ + ++i; printf("i = %d\n", i); return 0; } What do you think the answer to this question is? Don't look at the answers that follow!
There are many answers, and the results are different in different compilers, which means it's still cannot determine the result Hey, you still got the wrong answer, don't worry, just look at the rest of the question #include What do you think the answer to this question is? Don't look at the answers that follow!
The answer is Different results for different compilers Hey, did you get it wrong again? Don't worry, let's look at the rest of the question
④: #include This is the last question, how many have you gotten right so far? Please try in the comments. Hey!
The answer to this question is Different results for different compilers
How many questions did everyone answer correctly? Feel free to comment! 1. Now formally explain all the above questions designed to the content of -------- expressions to find the value The order in which expressions are evaluated is partly determined by the precedence and union of operators.
Similarly, some expressions have operands that may need to be converted to other types during the evaluation process. 1.1 Implicit type conversion (integer truncation and lifting) What is implicit type conversion, integer boosting, and integer truncation? C's integer arithmetic operations are always at least to meet the precision of the integer type to be performed.
To obtain this precision, an expression that has char and short types must be converted to integers before they can be used, a process called Integer Boosting
.
The process by which a larger data type is stored in a smaller data type is called Integer Truncation , such as the integer a = 500 , but a puts his value in the Character type b b cannot fully store a, and the Integer truncation
.
And this conversion behavior is called implicit type conversion 1.1.1 Explanation of the first question #include We know that everything in a computer is the complement of an operation. So it's the same here, (if you don't understand the original code and the inverse code, go to Baidu).
The original code, inverse code, and complement of a positive number are exactly the same
...for negative numbers, the complement is the inverse plus one, and the inverse is the inverse of the original code with all bits except the sign bit.
a has only 1 byte, and its complement is 00000011 (binary)
The b has only 1 byte, and its complement is 01111111 (binary)
a plus b, which is an arithmetic operation, needs to be raised to 4 bytes. And there are two ways to boost an integer
Arithmetic Boosting: Completes the first sign digit up to 32 bits Logical boosting: just fill in the zeros no matter what, up to 32 bits
Most calculators do arithmetic boosting , which is explained here Arithmetic Boosting . aAfter arithmetic lifting is 000000000000000000000000000000000011
bAfter the arithmetic boost is 000000000000000000000000000001111111
The result of a+b is ------ 000000000000000000000000000010000010
The integer truncation occurs because c is only 1 byte, so only the last 8 bits are accessed.
10000010
At this point c is accessing complement, and c is signed, Remember!!! When you print the code, it will be restored to the original code, and the number corresponding to the complement is -126 Here is a sheet of character types Original code complement inverse code The corresponding understanding diagram for
So the signed range is [-128,127]
The unsigned range is [0,255] It's better to turn it into a circle and find it yourself by the symbols.

1.1.2 Explanation of the second question

#include 

The binary of 0xb6 is 000000000000000000000000000010110110
Save it in a, truncate it, and get 1011 0110
The binary of 0xb600 is 00000000 00000000 10110110 00000000
The truncation occurs in b, and we get 10110110 00000000
0xb6000000 10110110 00000000 00000000 00000000
Save it in c just right.

a is now stored in the complement, and a is compared to 0xb6, which is involved in the operation, so the integer is raised to
11111111 11111111 11111111 10110110 ,

  • The integer boosted number is not the same as the 0xb6 binary, so it is not equal.

b is stored as a complement, and b is compared to 0xb600, which is involved in the operation, so it is integer-boosted to
11111111 11111111 10110110 00000000

  • The integer boosted number is not the same as the 0xb600 binary, so it is not equal

c is stored at this point as 10110110 00000000 00000000 00000000 Note that some people may ask 0xb6000000 is a positive number, Not !!!!! , literal constants are the default int type as long as they don't have a sign. So at this point 0xb6000000 is more than int, it is considered to be the complement of a negative binary number. So c and 0xb6000000 is equivalent.



1.1.3 Explanation of the third question

#include 

sizeof Measures the value of the type attribute.
c The type of the char The answer is 1, because there is only one byte
+c , + It is a monomial operator, and with c, the integer is raised to int, so it is 4 bytes, and the answer is 4
-c , and by the same token, still 4

1.2 Arithmetic conversions

As we said above, if the operand size is smaller than int, integer boosting occurs, but what if all types larger than or equal to int are involved in arithmetic operations? Here's where we get into the Arithmetic conversion .
What is an arithmetic conversion? For example, the following example:

#include 

The result will print a will be greater than b
Because this is an arithmetic conversion, i.e. it still needs to satisfy the same type of operation, unsigned int is higher than int, so the value of a will default to unsigned, and a will be larger than b.

Arithmetic boosting direction:


1.3 Operator Attributes

There are three factors that influence the valuation of complex expressions.

  1. Operator precedence
  2. Combinability of operators
  3. Whether to control the order of evaluation.

1.3.1 What is priority?

It's deciding what to calculate first. For example d = a + b*c . Because * has a higher priority than + , so the b*c and then calculate +

1.3.2 What is bonding?

It is the decision of which direction to calculate from, given the same priority. For example d = a * b * c because the successive * , the precedence is no longer useful, so it's a combination at this point, * The union is from left to right. This means that the a*b and then calculate *c .

1.3.3 What is the order of evaluation?

There are only a few operators in c that have evaluation order, such as ||, && , !
That order of values What exactly does that mean?
For example, a equals 0, b equals 2, and c equals 3, d = a && b && c The value of d ends up being 0, but it only goes as far as a when the operation is done, because && is as long as you encounter false is false, after the true or false is no longer relevant, a is 0, is false, so do not care about the next. That's the order of the values.

Here are two small exercises on the order of values:

#include 

The answer is 1 2 3 4 . Reason: a is a post ++, the value of a=0 is used first, it is encountered false at the beginning, and is not executed later. But a is still added, because the post-plus is is used first and then added

#include 

Answer: 1 2 3 4 The first ++, i.e., the first plus, a becomes 1, because || ends as soon as it meets true, and doesn't care if it's true or false. So only a changes.


Here's a table of operator properties:


Where the priority decreases from top to bottom

1.3.4 The fourth question explains

#include 

ret = c + --c There are two operation symbols in Priority , -- has a higher priority than + , so it was decided to count -c first, but + When is the c to the left of the number prepared? As we know, c is a compiled language, so after the code is written, it needs to be compiled into machine language first and then executed. So at compile time, the value to the left of the + sign is in the --c before it is compiled, or --c was compiled afterwards? It's not certain.

  • Under the vs compiler the answer is 4, which is the same as the --c After preparing the c
  • Under the gcc compiler the answer is 5, which is in the --c before preparing the c

So: this is the problem code, let's not write such garbage code in the future.

1.3.5 Explanation of the fifth problem

int main()
{
	 int i = 10;
	 i = i-- - --i * ( i = -3 ) * i++ + ++i;
	 printf("i = %d\n", i);
	 return 0;
}

This is the same thing, although the priority is known, it is not certain when the operands in the union are ready, and you can see the result of the operation in different compilers:

Again, it's a garbage code

1.3.6 Explanation of the sixth problem

#include 

() The function call symbol has the highest priority, but there are three of them, so which one should be called first? Again, it's not clear.

  • The vs compiler calls them from left to right, resulting in -10.
  • But what about other compilers? Try gcc, codeblocks, Devc++, and you'll see that it's completely different.

1.3.7 Explanation of the seventh question

Before saying more about this question, the blogger must criticize some colleges, why? Schools teach people ++ The symbols are not the most like to use this type to test everyone? Here to tell you clearly, this is a complete waste of time!!!! Because this code is meaningless!!!! is garbage code

#include 

First, () The parentheses have the highest priority, but there are three of them, so which one should we count first?
Second, a i change, will it affect the other one? I'm not sure here. It's the same as in question 4, where we said that before compiling c exactly when to prepare the same. Not sure.!!!

  • The value of the vs compiler is 12 4
  • The value for the gcc compiler is 10 4
    Different values for different compilers, different results, such code does not deserve to be called code.!!!!

So, if you see this kind of question in the future, just skip it, it doesn't make sense.

Summary:

  • Knowing what integer lifting and truncation are
  • Knew what an arithmetic conversion was
  • Knowing the properties of what operators are used, you can't write crap like this in the future.