<C language> operator

1. Arithmetic operators

  • Addition (+): Used to add two operands.
  • Subtraction (-): Used to subtract the second operand from the first operand.
  • Multiplication (*): Used to multiply two operands.
  • Division (/): Used to divide the first operand by the second operand.
  • Modulo (%): Used to find the remainder of the division of two operands.
void test1() {
    
    
    //int a = 5.0 % 2.0;  //err `%` 操作符的两个操作数必须为整数

    int a = 10;
    int b = 3;
    int sum = a + b;       // 加法
    int difference = a - b;// 减法
    int product = a * b;   // 乘法
    int quotient = a / b;  // 除法
    int remainder = a % b; // 取模

    printf("Sum: %d\n", sum);              //13
    printf("Difference: %d\n", difference);//7
    printf("Product: %d\n", product);      //30
    printf("Quotient: %d\n", quotient);    //3
    printf("Remainder: %d\n", remainder);  //1
}
  • Multiplication, division, and modulo have the same priority over addition and subtraction.

  • Operators with the same precedence are evaluated in left-to-right order, unless parentheses are used to change the precedence.

  • In expressions of mixed data types, the C language performs implicit type conversions, promoting lower data types to higher data types to perform correct calculations.

  • In addition %to the operator, several other operators work on integers and floating-point numbers.

  • For /the operator, if both operands are integers, integer division is performed. And as long as there are floating-point numbers, floating-point number division is performed.

  • %Both operands of the operator must be integers. Returns the remainder after division.

2. Shift operator

<< 左移操作符
>> 右移操作符
    
//注:移位操作符的操作数只能是整数。

2.1 Left shift operator

The left shift operator (<<) shifts all bits of a number to the left by the specified number of bits. After shifting, the lower bits are filled with zeros.

Discard on the left, add 0 to the right

insert image description here

void test2(){
    
    
    int a = 4;
	//00000000000000000000000000000100 - 4的补码
	
	int b = a << 1; //把a向左移动一位的值给b,a的值不变
    //b的补码:00000000000000000000000000001000 
	printf("a=%d b=%d\n", a, b);  //a=4 b=8
}
void test3() {
    
    
    int a = -4;
    //10000000000000000000000000000100 - -4的原码
    //11111111111111111111111111111011 - -4的反码
    //11111111111111111111111111111100 - -4的补码

    int b = a << 1;//把a向左移动一位
    //11111111111111111111111111111000 - b中存储的补码
    //11111111111111111111111111110111 - b的反码
    //10000000000000000000000000001000 - b的原码
    //-8
    printf("a=%d b=%d\n", a, b);   //a=-4 b=-8
}

2.2 Right shift operator

There are two types of right shift operations: logical right shift and arithmetic right shift.

  • Logical Right Shift: For unsigned integers, the logical right shift fills the upper bits with zeros.
  • Arithmetic Right Shift: For signed integers, arithmetic right shift fills the high bits with sign bits to keep the sign of the value unchanged.
  • Logical shift fills with 0 on the left and discards on the right
  • The left side of the arithmetic shift is filled with the sign bit of the original value, and the right side is discarded

insert image description here

void test4() {
    
    
    int a = -4;
    //10000000000000000000000000000100 - -4的原码
    //11111111111111111111111111111011 - -4的反码
    //11111111111111111111111111111100 - -4的补码

    int b = a >> 1;//
    //11111111111111111111111111111100
    //11111111111111111111111111111110 - b在内存中的补码
    //11111111111111111111111111111101 - b的反码
    //10000000000000000000000000000010 - b的原码
    //-2
    printf("a=%d b=%d\n", a, b);  //a=-4 b=-2
}
void test5() {
    
    
    int a = 4;
    //00000000000000000000000000000100 补码
    
    int b = a >> 1;
    //00000000000000000000000000000010
    printf("a=%d b=%d\n", a, b);  //a=4 b=2
}

Notice:

For shift operators, don't shift negative bits, this is undefined by the standard.

int num = 10;
num>>-1;//error

3. Bitwise operators

  1. Bitwise AND (&): Performs a logical AND operation on the corresponding bits of the two operands to generate a new value.
  2. Bitwise OR (|): Performs a logical OR operation on the corresponding bits of the two operands to generate a new value.
  3. Bitwise XOR (^): Perform logical XOR operation on the corresponding bits of the two operands to generate a new value. The resulting bit is 0 if the two bits are the same, and 1 otherwise.
  4. Bitwise inversion (~): Performs a logical inversion operation on all bits of an operand, changing 1 to 0 and 0 to 1.

Note: Their operands must be integers.

void test6() {
    
    
    int a = 3;
    int b = -5;
    int c = a & b;//& - 按(2进制)位与
    printf("%d\n", c);    //3

    //
    //00000000000000000000000000000011 - 3的补码
    //10000000000000000000000000000101 -5的原码
    //11111111111111111111111111111010 -5的反码
    //11111111111111111111111111111011 -5的补码
    
    //补码计算
    //00000000000000000000000000000011
    //11111111111111111111111111111011
    //00000000000000000000000000000011 - 3
}
void test7() {
    
    
    int a = 3;
    int b = -5;
    int c = a | b;//& - 按(2进制)位或
    printf("%d\n", c);

    //
    //00000000000000000000000000000011 -> 3的补码
    //10000000000000000000000000000101 -5的原码
    //11111111111111111111111111111010 -5的反码
    //11111111111111111111111111111011 -5的补码
    //
    //00000000000000000000000000000011
    //11111111111111111111111111111011
    //11111111111111111111111111111011   得到的补码结果需要转换成原码
    //11111111111111111111111111111010   -1得到反码
    //10000000000000000000000000000101 -> -5
}
void test8() {
    
    
    int a = 3;
    int b = -5;
    int c = a ^ b;//& - 按(2进制)位异或
    printf("%d\n", c);
    //异或的运算:相同为0,相异为1
    //
    //00000000000000000000000000000011 -> 3的补码
    //10000000000000000000000000000101 -5的原码
    //11111111111111111111111111111010 -5的反码
    //11111111111111111111111111111011 -5的补码
    //
    //00000000000000000000000000000011
    //11111111111111111111111111111011   
    //11111111111111111111111111111000   //补码亦或结果
    //11111111111111111111111111110111   //-1得到反码
    //10000000000000000000000000001000   //原码
    //-8
}

exercise 1

A temporary variable (the third variable) cannot be created to exchange two numbers.

void test9() {
    
    
    int a = 10;
    int b = 20;
    a = a ^ b;
    b = a ^ b;   //b=a^b^b   b^b=0  0^a=a  b=a
    a = a ^ b;   //a=a^a^b   a=b
    printf("a = %d b = %d\n", a, b);   //a = 20 b = 10
}

exercise 2

Write code to achieve: Find the number of 1s in the binary of an integer stored in memory.

//方法1:
#include <stdio.h>
int main() {
    
    
    int num = 10;
    int count = 0;//计数
    while (num) {
    
    
        if (num % 2 == 1)
            count++;
        num = num / 2;
    }
    printf("二进制中1的个数 = %d\n", count);
    return 0;
}
//思考这样的实现方式有没有问题?

//方法2:
#include <stdio.h>
int main() {
    
    
    int num = -1;
    int i = 0;
    int count = 0;//计数
    for (i = 0; i < 32; i++) {
    
    
        if (num & (1 << i))
            count++;
    }
    printf("二进制中1的个数 = %d\n", count);
    return 0;
}

//思考还能不能更加优化,这里必须循环32次的。
//方法3:
#include <stdio.h>
int main() {
    
    
    int num = -1;
    int i = 0;
    int count = 0;//计数
    while (num) {
    
    
        count++;
        num = num & (num - 1);
    }
    printf("二进制中1的个数 = %d\n", count);
    return 0;
}
//这种方式是不是很好?达到了优化的效果,但是难以想到。

4. Assignment operator

  1. Simple assignment (=): assigns the value of the expression on the right to the variable on the left. For example: a = 10;means to assign the value 10 to the variable a.
  2. Addition assignment (+=): Add the value of the expression on the right to the variable on the left, and assign the result to the variable on the left. For example: a += 5;it means adding 5 to the value of variable a and then assigning it to a.
  3. Subtraction assignment (-=): Subtracts the value of the expression on the right from the variable on the left and assigns the result to the variable on the left. For example: a -= 3;it means that the value of variable a is subtracted by 3 and then assigned to a.
  4. Multiplication assignment (*=): Multiply the value of the expression on the right by the variable on the left, and assign the result to the variable on the left. For example: a *= 2;means that the value of variable a is multiplied by 2 and then assigned to a.
  5. Division assignment (/=): Divides the value of the variable on the left by the value of the expression on the right and assigns the result to the variable on the left. For example: a /= 4;it means that the value of variable a is divided by 4 and then assigned to a.
  6. Modulo assignment (%=): Divide the value of the variable on the left modulo by the value of the expression on the right, and assign the remainder to the variable on the left. For example: a %= 7;means assigning the remainder of the value of variable a to a modulo 7 to a.
  7. Left shift assignment (<<=): Shift the value of the left variable to the left by the number of digits specified by the right expression, and assign the result to the left variable. For example: a <<= 3;it means to shift the value of variable a to the left by 3 bits and then assign it to a.
  8. Right-shift assignment (>>=): Shift the value of the variable on the left by the number of digits specified by the expression on the right, and assign the result to the variable on the left. For example: a >>= 2;it means to shift the value of variable a to the right by 2 bits and then assign it to a.
  9. Bitwise AND assignment (&=): Perform a bitwise AND operation between the value of the variable on the left and the value of the expression on the right, and assign the result to the variable on the left. For example: a &= b;means assigning the result of the bitwise AND operation between variable a and variable b to a.
  10. Bitwise OR assignment (|=): Perform a bitwise OR operation between the value of the variable on the left and the value of the expression on the right, and assign the result to the variable on the left. For example: a |= b;means assigning the result of the bitwise OR operation between variable a and variable b to a.
  11. Bitwise XOR assignment (^=): Perform a bitwise XOR operation between the value of the variable on the left and the value of the expression on the right, and assign the result to the variable on the left. For example: a ^= b;means assigning the result of the bitwise XOR operation between variable a and variable b to a.

5. Unary operator

  1. Increment (++): Increase the value of the operand by 1. There are two usages of prefix and suffix:
    • Prefix increment: ++operand, first increment the operand by 1, and then return the incremented value.
    • Suffix auto-increment: operand++, first returns the value of the operand, and then adds 1 to the operand.
  2. Decrement (–): Decreases the value of the operand by 1. There are two usages of prefix and suffix:
    • Prefix decrement: –operand, first decrement the operand by 1, and then return the reduced value.
    • Suffix decrement: operand–, return the value of the operand first, and then decrement the operand by 1.
  3. Get address (&): Get the address of the operand, that is, return the address of the operand in memory.
  4. Dereference (*): Used to access the value at the memory address pointed to by the pointer.
  5. Positive sign (+): Returns the positive value of the operand.
  6. Negative sign (-): Returns the negative value of the operand.
  7. Logical NOT (!): Performs a logical NOT operation on the operands, returning 1 if the operand is 0 and 0 if the operand is non-zero.
  8. Bitwise inversion (~): Inverts each bit of the operand, that is, 0 is changed to 1, and 1 is changed to 0.
  9. (type): cast
//=  +=
void test(){
    
    
    int a = 10;
	int b = 0;
	b = a = a + 3;
	printf("a=%d b=%d\n", a, b);   //a=13,b=13
    a += 1;
    printf("a=%d\n",a);  //a=14
}
//-
void test() {
    
    
    int flag = 0;
    if (!flag) {
    
    //!flag不等于0就运行
        printf("hehe\n");
    }
}
//& *
void test() {
    
    
    int a = 10;//4
    char c = 0;//1
    
    printf("%p\n", &a);    //打印a的地址:000000000061FDE4
    printf("%p\n", &c);    //打印c的地址:000000000061FDE3

    int *pa = &a;//& - 取地址操作符
    *pa = 20;//* - 解引用操作符
    printf("%d\n",a);    //20 
    
    int arr[10];
    //	&arr;//取出数组的地址
    
    //野指针 - 问题
	//*(int*)0x0012ff40 = 100;
}
//~
void test() {
    
    
    int a = 0;
    //00000000000000000000000000000000
    //11111111111111111111111111111111 - 内存中-补码
    //11111111111111111111111111111110
    //10000000000000000000000000000001

    printf("%d\n", ~a);    //-1
}
//| &
void test() {
    
    
    int a = 10;
    int n = 0;
    scanf("%d", &n);
    //把a的第n位置为1
    a = a | (1 << (n - 1));
    printf("a=%d\n", a);

    //把a的第n位置为0
    a = a & ~(1 << (n - 1));
    printf("a=%d\n", a);

    //00000000000000000000000000001010
    //00000000000000000000000000010000
    //1<<2;
    //00000000000000000000000000011010
    //11111111111111111111111111101111
    //00000000000000000000000000010000
    //00000000000000000000000000001010
}
//前置++和--
#include <stdio.h>
int main() {
    
    
    int a = 10;
    int x = ++a;
    //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
    int y = --a;
    //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
    return 0;
}
//后置++和--
#include <stdio.h>
int main() {
    
    
    int a = 10;
    int x = a++;
    //先对a先使用,再增加,这样x的值是10;之后a变成11;
    int y = a--;
    //先对a先使用,再自减,这样y的值是11;之后a变成10;
    return 0;
}
//(类型)
void test() {
    
    
   	int a = (int)3.14;
	printf("%d\n", a);  //3
}

5.1 sizeof and arrays

sizeofis an operator used to get the size in bytes of a data type or expression. It can be used for type names, variables, arrays and expressions.

void test() {
    
    
    short s = 10;
    int a = 2;
    s = a + 5;

    printf("%zu\n", sizeof(s = a + 5));//2

    printf("%d\n", s);//7


    int b = 10;
    int *p;
    int arr[10];

    printf("%zu\n", sizeof(b));  //int  4
    printf("%zu\n", sizeof b);   //int  4
    printf("%zu\n", sizeof(int));//int  4
    //printf("%zu\n", sizeof int); //err 


    printf("%zu\n", sizeof(p));      //int* 4
    printf("%zu\n", sizeof(arr));    //int [10] 40
    printf("%zu\n", sizeof(arr[10]));//int 4
}

sizeof intis illegal because sizeofthe operator requires a parenthesized data type or expression when used.

#include <stdio.h>

void test1(int arr[]) {
    
    
    printf("%zu\n", sizeof(arr));  // 输出指针的大小,通常为4或8
}

void test2(char ch[]) {
    
    
    printf("%zu\n", sizeof(ch));   // 输出指针的大小,通常为4或8
}

int main() {
    
    
    int arr[10] = {
    
    0};
    char ch[10] = {
    
    0};
    printf("%zu\n", sizeof(arr));   // 输出数组的大小,40字节
    printf("%zu\n", sizeof(ch));    // 输出数组的大小,10字节
    test1(arr);
    test2(ch);
    return 0;
}

When an array is passed as a function parameter, it is actually converted to a pointer type. arrTherefore, formal parameters and sums in functions chare treated as pointers, not arrays. In this case, using sizeofthe operator to get the size of the pointer will get you the size of the pointer itself, not the size of the pointed-to array.

6. Relational Operators

Relational operators are used to compare the values ​​of two expressions and return a Boolean value (0 or 1) indicating whether the comparison is true or false.

  1. Equality (==): Checks whether the two operands are equal, and returns 1 if they are equal, or 0 otherwise.
  2. Not Equal (!=): Checks if the two operands are not equal and returns 1 if not, 0 otherwise.
  3. Greater than (>): Checks if the left operand is greater than the right operand, returns 1 if it is, 0 otherwise.
  4. Less Than (<): Checks if the left operand is less than the right operand, returns 1 if it is, 0 otherwise.
  5. Greater than or equal to (>=): Checks if the left operand is greater than or equal to the right operand, returns 1 if it is, 0 otherwise.
  6. Less than or equal to (<=): Checks if the left operand is less than or equal to the right operand, returns 1 if it is, 0 otherwise.

These relational operators are relatively simple, there is nothing to talk about, but we should pay attention to the pitfalls when using some operators.

Note: In the process of programming, == and = are accidentally written wrong, resulting in errors.

7. Logical operators

  1. Logical AND (&&): Returns 1 when both operands are true (non-zero); otherwise returns 0. If the left operand is false, the right operand is not evaluated.
  2. Logical OR (||): Returns 1 when at least one of the two operands is true (nonzero); otherwise returns 0. If the left operand is true, the right operand is not evaluated.
  3. Logical NOT(!): Performs a logical NOT operation on the operands, returning 1 if the operands are zero and 0 if the operands are non-zero.

These logical operators are usually used in conditional judgment, loop control and Boolean expressions to combine and manipulate Boolean values ​​to obtain the final logical result.

#include <stdio.h>

int main() {
    
    
    int a = 5;
    int b = 3;
    int c = 0;

    printf("a > b && b > c: %d\n", a > b && b > c);   // 输出:1,因为a > b和b > c都为真
    printf("a > b || b > c: %d\n", a > b || b > c);   // 输出:1,因为a > b为真
    printf("!c: %d\n", !c);                           // 输出:1,因为c为0

    return 0;
}

It should be noted that logical operators have the property of short-circuit evaluation. The logical AND operator (&&) does not evaluate the right operand when the left operand is false; the logical or operator (||) does not evaluate the right operand when the left operand is true. This feature can be used to avoid unnecessary calculations and improve program efficiency.

Pen questions

#include <stdio.h>
int main() {
    
    
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++ && ++b && d++;
    printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
    return 0;
}
//程序输出的结果是什么?

In a given program, logical operations are performed on multiple expressions through the logical AND operator (&&), and the result is assigned to the variable i. According to the evaluation rules of the logical AND operator, if the left operand is true, the right operand will continue to be evaluated, and if the left operand is false, the right operand will not be evaluated.

According to the expression in the code a++ && ++b && d++, the following evaluation process can be performed:

  1. a++: The value of a is 0, and then a is incremented by 1. The result of the expression is 0.
  2. Since the left operand is false (non-zero), the sum of the right operand ++bis d++not calculated.

According to the evaluation rules of the logical AND operator, the result of the entire expression is false (0). Therefore, the variable i is assigned the value 0.

The output is:

a = 1
b = 2
c = 3
d = 4
#include <stdio.h>
int main() {
    
    
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++||++b||d++;
    printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
    return 0;
}
//程序输出的结果是什么?

In a given program, logical operations are performed on multiple expressions through the logical OR operator (||), and the result is assigned to the variable i. According to the evaluation rules of the logical OR operator, if the left operand is true, the right operand will not be evaluated, and the result of the entire expression will be true (non-zero); if the left operand is false, the right operation will continue to be evaluated number, the result of the entire expression is true (nonzero) if the right operand is true, and false (0) otherwise.

According to the expression in the code a++ || ++b || d++, the following evaluation process can be performed:

  1. a++: The value of a is 0, and then a is incremented by 1. The expression evaluates to false (0).
  2. ++b: Since the left operand is false (0), the calculation of the right operand is performed. The value of b is 2, and then b is incremented by 1. The expression evaluates to true (nonzero).

Since at least one of the first two operands is true, the result of the entire expression is true (nonzero). Therefore, the variable i is assigned the value 1.

The output is:

a = 1
b = 3
c = 3
d = 4

8. Conditional Operators

The conditional operator (also known as the ternary operator) is a special operator used to select one of two expressions to evaluate based on a condition. Its grammatical form is as follows:

condition ? expression1 : expression2

Among them, condition is a conditional expression, and expression1 and expression2 are two possible result expressions. The conditional operator is evaluated as follows:

  1. First evaluate the conditional expression condition.
  2. If the conditional expression evaluates to true (non-zero), the entire conditional operator evaluates to the value of expression1.
  3. If the conditional expression evaluates to false (0), the entire conditional operator evaluates to the value of expression2.
#include <stdio.h>

int main() {
    
    
    int a = 5;
    int b = 3;

    int max = (a > b) ? a : b;  // 如果a大于b,则max为a的值;否则max为b的值

    printf("Max value: %d\n", max);

    return 0;
}

In the above example, the conditional operator is used (a > b) ? a : bto select the larger of the two numbers and assign it to the variable max. If a is greater than b, the value of max is a; otherwise, the value of max is b. The output is the larger value.

9. Comma expressions

A comma expression (comma expression) is a special expression that allows commas to be used in an expression to connect multiple subexpressions and evaluate them sequentially. Comma expressions are evaluated from left to right, and the return value is the value of the last subexpression.

  • Comma expressions are multiple expressions separated by commas.
  • Comma expressions are executed sequentially from left to right. The result of the entire expression is the result of the last expression.

The syntax for a comma expression is as follows:

expression1, expression2, expression3, ..., expressionN

Among them, expression1, expression2, expression3, etc. are all subexpressions, which can be any valid expressions.

#include <stdio.h>

int main() {
    
    
    int a = 5;
    int b = 3;
    int c;

    c = (a++, b++, a + b);  // 逗号表达式:先执行a++,再执行b++,最后求a + b

    printf("c = %d\n", c);  // 输出c的值,结果为10

    return 0;
}

In the above example, (a++, b++, a + b)the three subexpressions are concatenated using the comma expression . First execute a++, increase the value of a by 1, then execute b++, increase the value of b by 1, and finally calculate the result of a + b to be 10. This result is assigned to the variable c, and then the value of c is output.

10. Subscript references, function calls, and structure members

1. [ ] subscript reference operator

Operand: an array name + an index value

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
//[ ]的两个操作数是arr和9。

2. ( ) function call operator

Accepts one or more operands: the first operand is the function name, and the remaining operands are the parameters passed to the function.

#include <stdio.h>
void test1() {
    
    
    printf("hehe\n");
}

void test2(const char *str) {
    
    
    printf("%s\n", str);
}

int main() {
    
    
    test1();            //()作为函数调用操作符。
    test2("hello bit.");//()作为函数调用操作符。
    return 0;
}

3. Accessing members of a structure

.struct.membername

-> structure pointer -> member name

#include <stdio.h>
struct Stu {
    
    
    char name[10];
    int age;
    char sex[5];
    double score;
};

void set_age1(struct Stu stu) {
    
    
    stu.age = 18;
}

void set_age2(struct Stu *pStu) {
    
    
    pStu->age = 18;//结构成员访问
}

int main() {
    
    
    struct Stu stu;
    struct Stu *pStu = &stu;//结构成员访问

    stu.age = 20;//结构成员访问
    set_age1(stu);

    pStu->age = 20;//结构成员访问
    set_age2(pStu);
    return 0;
}

11. Expression Evaluation

The order in which expressions are evaluated is determined in part by the precedence and associativity of operators. Likewise, operands of some expressions may need to be converted to other types during evaluation.

11.1 Implicit type conversions

Implicit type conversion (implicit type conversion) refers to the type conversion that occurs automatically in the expression, without the need to explicitly use the type conversion operator. Implicit type conversion is determined by the type rules and expression evaluation rules of the C language.

Here are some common implicit type conversion situations:

  1. Integer promotion: When smaller integer types are involved in operations, they are automatically promoted to larger integer types. For example, when operating with intand , they are promoted to the type.shortshortint
  2. Floating-point promotion: When smaller floating-point types are involved in operations, they are automatically promoted to larger floating-point types. For example, when operating with floatand , they are promoted to the type.doublefloatdouble
  3. Integer conversion: When integer types of different sizes are assigned or mixed, the smaller integer type is automatically converted to a larger integer type. For example, when shortassigning to int, or when operating intwith .long
  4. Floating-point conversion: When floating-point types of different sizes are assigned or mixed, the smaller floating-point type will be automatically converted to a larger floating-point type. For example, when floatassigning to double, or when operating floatwith .double
  5. Mixed type operation: In an expression, when operands of different types are operated on, implicit type conversion occurs so that they have the same type. For example, when performing operations on integers and floating-point numbers, the integers are converted to floating-point numbers.

It should be noted that implicit type conversion may cause precision loss or data overflow problems. To avoid unintended type conversions and data loss, it is recommended to use explicit type conversion operators when required to perform explicit type conversions.

C's integer arithmetic operations are always performed with at least the precision of the default integral type. To achieve this precision, character and short integer operands in expressions are converted to plain integer types before use, a conversion known as integer promotion .

Significance of integer promotion:

The integer operation of the expression must be executed in the corresponding operation device of the CPU. The byte length of the operand of the integer arithmetic unit (ALU) in the CPU is generally the byte length of int, and it is also the length of the general-purpose register of the CPU.

Therefore, even if the addition of two char types is actually performed by the CPU, it must first be converted to the standard length of the integer operand in the CPU.

It is difficult for a general-purpose CPU (general-purpose CPU) to directly add two 8-bit bytes directly (although there may be such byte addition instructions in machine instructions). Therefore, the various integer values ​​in the expression whose length may be smaller than the length of int must be converted to int or unsigned int before being sent to the CPU for calculation.

//实例1
char a,b,c;
...
a = b + c;

The values ​​of b and c are promoted to normal integers before the addition operation is performed.

After the addition operation is complete, the result is truncated before being stored in a.

How to carry out overall improvement?

Integer promotion is done according to the sign bit of the data type of the variable

//负数的整型提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为char为有符号的 char
所以整型提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整型提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整型提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整型提升,高位补0

Examples of integer promotions:

//实例1
int main() {
    
    
    char a = 0xb6;
    short b = 0xb600;
    int c = 0xb6000000;
    if (a == 0xb6)
        printf("a");
    if (b == 0xb600)
        printf("b");
    if (c == 0xb6000000)
        printf("c");
    return 0;
}

In Example 1, a and b need to be plastic-upgraded, but c does not need plastic-uplifting. After a and b are plastic-uplifted, they become negative numbers, so the a==0xb6 , b==0xb600result of the expression is false, but c does not undergo plastic-uplifting. The expression c= =0xb6000000 is true

The output of the program is: c

//实例2
int main() {
    
    
    char c = 1;
    printf("%u\n", sizeof(c));
    printf("%u\n", sizeof(+c));
    printf("%u\n", sizeof(-c));
    return 0;
}

In example 2, as long as c participates in the expression operation, integer promotion will occur, and the expression +cwill be promoted, so sizeof(+c)it is 4 bytes. The expression -cwill also undergo integer promotion, so sizeof(-c)it is 4 bytes, However sizeof(c), it is 1 byte.

12. Properties of operators

There are three factors that affect the evaluation of complex expressions. 1. The priority of the operator 2. The associativity of the operator 3. Whether to control the order of evaluation. Which of two adjacent operators is executed first? Depends on their priorities. If both have the same priority, it depends on their associativity.

Operator precedence:

priority operator result type Combination Controlling the order of evaluation
1 () - left yes
2 [] - left yes
-> - left yes
. - left yes
++ same type right yes
same type right yes
(type) converted type right yes
sizeof size_t type right yes
3 ++ same type left yes
same type left yes
+ same type right yes
- same type right yes
! int type right yes
~ int type right yes
* same type right yes
& same type right yes
(type) converted type right yes
sizeof size_t type right yes
4 * same type left yes
/ same type left yes
% same type left yes
5 + same type left yes
- same type left yes
6 << same type left yes
>> same type left yes
7 < int type left yes
<= int type left yes
> int type left yes
>= int type left yes
8 == int type left yes
!= int type left yes
9 & same type left yes
10 ^ same type left yes
11 | same type left yes
12 && int type left yes
13 || int type left yes
14 ?: According to operand right yes
15 = left operand type right yes
+= left operand type right yes
-= left operand type right yes
*= left operand type right yes
/= left operand type right yes
%= left operand type right yes
<<= left operand type right yes
>>= left operand type right yes
&= left operand type right yes
^= left operand type right yes
|= left operand type right yes
16 , right operand type left yes

some question expressions

//表达式的求值部分由操作符的优先级决定。
//表达式1
a*b + c*d + e*f

Note: When calculating code 1, since it has a higher priority than +, it can only be guaranteed that the calculation of * is earlier than +, but the priority does not determine that the third one is executed earlier than the first +. So the computer order of expressions might be:

a*b
c*d
a*b + c*d
e*f
a*b + c*d + e*f
或者:
a*b
c*d
e*f
a*b + c*d
a*b + c*d + e*f
//表达式2
c + --c;

As above, the priority of the operator can only determine whether the operation of self-decrement – ​​is before the operation of +, but we have no way to know whether the acquisition of the left operand of the + operator is evaluated before or after the right operand, so The results are unpredictable and ambiguous.

//代码3-非法表达式
int main() {
    
    
    int i = 10;
    i = i-- - --i * (i = -3) * i++ + ++i;
    printf("i = %d\n", i);
    return 0;
}

Expression 3 Test results in different compilers: Result of illegal expression program

//代码4
int fun(){
    
    
     static int count = 1;
     return ++count;
}

int main(){
    
    
     int answer;
     answer = fun() - fun() * fun();
     printf( "%d\n", answer);//输出多少?
     return 0;
}

Although the results are the same on most compilers.

But answer = fun() - fun() * fun();in the above code, we can only know through the priority of the operator: first calculate the multiplication, and then calculate the subtraction.

The order in which functions are called cannot be determined by the precedence of operators.

//代码5
#include <stdio.h>
int main() {
    
    
    int i = 1;
    int ret = (++i) + (++i) + (++i);
    printf("%d\n", ret);
    printf("%d\n", i);
    return 0;
}

When the first + in this code is executed, whether the third ++ is executed is uncertain, because it is impossible to determine the first + and the third former depending on the priority and associativity of the operator. Set the sequence of ++.

Summary: If the expression we write cannot determine the only calculation path through the attributes of the operator, then there is a problem with this expression.

Guess you like

Origin blog.csdn.net/ikun66666/article/details/131465475