목차
1. 운영자 분류:
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
2. 산술 연산자
+ - * / %
1. % 연산자 외에도 여러 다른 연산자가 정수 및 부동 소수점 숫자에 대해 작동할 수 있습니다.
2. / 연산자는 두 피연산자가 모두 정수이면 정수 나눗셈을 한다. 그리고 부동 소수점 숫자가 있는 한 부동 소수점 숫자 나눗셈이 수행됩니다.
3. % 연산자의 두 피연산자는 정수여야 합니다. 나누기 후 나머지 반환
3. 시프트 연산자
<< 왼쪽 시프트 연산자는 이진 시퀀스를 왼쪽으로 이동합니다.
>> 오른쪽 시프트 연산자는 이진 시퀀스를 오른쪽으로 이동합니다.시프트 연산자에 대해 말하면 바이너리에 대해 이야기하려고 합니다.
정수의 이진 비트 표현에는 세 가지 형식이 있습니다. 원래 코드 보완 코드 역 코드
양의 정수의 원래 코드와 보수 코드는 동일합니다.
음수 정수의 보수와 보수를 계산해야 합니다.
부호 비트 0 - 양수를 나타냅니다.
1 - 음수를 나타냅니다.
정수는 메모리의 2의 보수에 저장됩니다.
int a = 5
原码 000000000000000000000000000000000101
反码 000000000000000000000000000000000101
补码 000000000000000000000000000000000101
int a = -5
原码 10000000000000000000000000000101
反码 11111111111111111111111111111010 (原码的符号位不变,其他位取反的就是补码)
补码 11111111111111111111111111111011 (反码+1就是补码)
3.1 왼쪽 시프트 연산자
왼쪽 시프트: 이진 시퀀스의 왼쪽을 버리고 오른쪽에 0을 더하는 것입니다.
int main()
{
int a = 5;
int b = a << 1;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
프로그램 실행 결과
int main()
{
int a = -5;
int b = a << 1;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
프로그램 실행 결과
참고: 컴파일러가 출력한 값은 모두 원본 코드입니다.
음수의 원래 부호와 여 부호의 여수 변환 규칙
3.2 오른쪽 시프트 연산자
오른쪽으로 2개로 이동
산술 오른쪽 시프트: 오른쪽을 버리고 왼쪽을 원래 부호 비트로 채웁니다.
논리적 오른쪽 시프트: 오른쪽에서 버리고 왼쪽에 0 추가
산술 오른쪽 시프트인지 논리적 오른쪽 시프트인지는 컴파일러에 달려 있습니다.
참고: 시프트 연산자의 경우 음수 비트를 시프트하지 마십시오. 이는 표준에서 정의되지 않습니다.
4. 비트 연산자
& //(이진) 비트에 따라 그리고 (해당 이진 비트가 0인 한 0이고, 1만 모두 1) | // (이진) 비트에
따라 또는 (해당하는 한 이진 비트는 1, 1, 모든 0은 0)
^ // 배타적 또는 (이진) 비트 (해당 이진 비트는 0이고 다른 비트는 1)
참고: 해당 피연산자는 정수여야 합니다.
int main()
{
int a = 3;
int b = -5;
int c = a & b;
int d = a | b;
int e = a ^ b;
printf("%d\n", c);
printf("%d\n", d);
printf("%d\n", e);
return 0;
}
00000000000000000000000000000011 -> 3的补码
11111111111111111111111111111011 -> -5的补码
(再次提醒,编译器打印出来的是原码,而正数原码反码补码相同)
00000000000000000000000000000011 -> 3&-5的结果 结果是3
(补码)
11111111111111111111111111111011 -> 3|-5的结果
10000000000000000000000000000101 (原码) 结果是-5
(补码)
11111111111111111111111111111000 -> 3^-5的结果
10000000000000000000000000001000 (原码) 结果是-8
프로그램 실행 결과
왜곡된 인터뷰 질문:
두 숫자의 교환을 실현하기 위한 임시 변수(세 번째 변수)를 생성할 수 없습니다.
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("a = %d b = %d\n", a, b);
return 0;
}
초보자는 그것을 알기를 기대하지 않고 그러한 방법이 있다는 것을 알고 있습니다.
5. 할당 연산자
대입 연산자는 이전에 만족하지 못했던 값을 얻을 수 있게 해주는 훌륭한 연산자입니다. 즉, 자신을 재지정할 수 있습니다.
int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值
복합 할당 연산자
+= -= *= /= %= >>= <<= &= |= ^=
예: int x += 2 ; //x = x+2
6. 단항 연산자
6.1 단항 연산자 소개
!논리 역연산
- 음수
+ 양수
&
피연산자 유형 길이의 주소 크기(바이트)
~ 숫자의 이진 비트 반전
-- 전치사, 후치사 --
++ 전치사, 후위사 ++
* 간접 연산자(역참조 연산자)
( 유형) 캐스트
C 언어에서 0은 거짓을 의미하고 0이 아닌 것은 참을 의미합니다.
int num =10;
if(num)
{
printf("hehe\n);
}
//!num 就是假 if语句不进入
1. sizeof(배열 이름), 배열 이름은 배열의 첫 번째 요소의 주소가 아니며, 배열 이름은 전체 배열을 나타내며 계산은 전체 배열의 크기입니다.이 경우를 제외하고 모든 배열 이름은 배열의 첫 번째 요소의 주소를 나타냅니다 .
sizeof는 함수가 아닌 연산자로 타입별로 생성된 변수가 차지하는 메모리의 크기를 계산하며 단위는 byte이다.
sizeof()의 표현식은 계산에 참여하지 않습니다.
sizeof에 대한 불쾌한 질문
#include <stdio.h>
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
Q: 프로그램은 무엇을 출력합니까?
설명: 먼저 전역 변수가 초기화되지 않으면 기본적으로 0으로 설정되므로 이때 i의 값은 0이고 sizeof 연산자의 반환 값은 size_t이며 size_t는 부호 없는 숫자를 나타내며, 여기서 이 표현식은 산술 변환(i > sizeof(i))을 수행해야 하며 컴파일러는 자동으로 왼쪽 i를 무부호 정수 데이터로 변환합니다.-1에 해당하는 무부호 정수는 4 또는 8을 초과하는 매우 큰 수입니다. 따라서 최종 결과는 ">"를 인쇄하는 것입니다.
&는 주소 및 * 간접 액세스 연산자(역참조 연산자)를 사용합니다.
int main()
{
//& 取地址操作符
//* 解引用操作符(间接访问操作符)
int a = 10;
int* pa = &a;
*pa = 20;//* - 解引用操作符
//
//*&a ==> a;
return 0;
}
7. 관계 연산자
> >= < <= != ==
할말이 없다
8. 논리 연산자
&& 논리 및
|| 논리 또는논리 AND 왼쪽과 오른쪽이 모두 참일 때만 전체 식이 참
논리적이거나 왼쪽과 오른쪽 표현식이 모두 거짓인 경우에만 전체 표현식이 거짓입니다.
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
//i = a++ && ++b && d++;
i = a++ || ++b || d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
분석: i = a++ || ++b || d++; a++는 첫 번째, 다음 ++, ay는 0에서 시작하여 내려가고, ++b, 첫 번째 b++를 사용하고 전체 표현식의 값을 사용하는 경우 가 이미 참이면 다음 d++는 실행되지 않으므로 프로그램의 실행 결과는 1 , 3 , 3 , 4입니다.
9. 조건 연산자
특급1 ? 특급2 : 특급3
문장 1이 참이면 식의 결과는 문장 2이고 그렇지 않으면 문장 3입니다.
int main()
{
int a = 3;
int b = 5;
int m = (a > b ? a : b);
printf("%d\n", m);
return 0;
}
10. 쉼표 표현
쉼표 식은 쉼표로 구분된 여러 식입니다.
쉼표 식은 왼쪽에서 오른쪽으로 순차적으로 실행됩니다. 전체 식의 결과는 마지막 식의 결과입니다.
int main()
{
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);
printf("a=%d b=%d\n", a, b);
printf("%d\n", c);
return 0;
}
11. 첨자 참조, 함수 호출 및 구조체 멤버
1. [ ] 첨자 참조 연산자
피연산자: 배열 이름 + 인덱스 값
int arr[10];//배열 생성
arr[9] = 10;//실용적인 첨자 참조 연산자.
[ ]의 두 피연산자는 arr과 9입니다.2. ( ) 함수 호출 연산자는
하나 이상의 피연산자를 허용합니다. 첫 번째 피연산자는 함수 이름이고 나머지 피연산자는 함수에 전달된 매개변수입니다.참고: 매개변수가 없을 수 있습니다.
3. 구조체의 멤버에 접근
. 구조체 . 멤버 이름
-> 구조체 포인터 -> 멤버 이름
#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;
}
12. 표현 평가
표현식이 평가되는 순서는 부분적으로 연산자의 우선 순위와 연관성에 따라 결정됩니다.
마찬가지로 일부 표현식의 피연산자는 평가 중에 다른 유형으로 변환해야 할 수 있습니다.
12.1 암시적 유형 변환
C의 정수 산술 연산은 항상 최소한 기본 정수 유형의 정밀도로 수행됩니다. 이 정밀도를 달성하기 위해 표현식의 문자 및 짧은 정수 피연산자는 사용하기 전에 일반 정수 유형으로 변환되며, 이는 정수 승격으로 알려진 변환입니다.
정수 승격 의 의미 :
표현의 정수 연산은 CPU의 해당 컴퓨팅 장치에서 실행되어야 합니다.CPU에서 정수 산술 단위(ALU)의 피연산자의 바이트 길이는 일반적으로 int의 바이트 길이이며, CPU의 바이트 길이이기도 하며 범용 레지스터의 길이이기도 합니다. 따라서 두 char 타입의 추가가 실제로 CPU에서 수행되더라도 먼저 CPU에서 정수 피연산자의 표준 길이로 변환되어야 합니다. 범용 CPU(general-purpose CPU)가 직접 2개의 8비트 바이트를 추가하는 것은 어렵습니다(비록 머신 명령어에 이러한 바이트 추가 명령이 있을 수 있음). 따라서 길이가 int보다 작을 수 있는 표현식의 다양한 정수 값은 계산을 위해 CPU로 전송되기 전에 int 또는 unsigned int로 변환되어야 합니다.
문자 a,b,c;
...
a = b + c;b와 c의 값은 더하기 연산이 수행되기 전에 일반 정수로 승격됩니다.
더하기 연산이 완료된 후 결과는 a에 저장되기 전에 잘립니다.
전반적인 개선을 수행하는 방법?
정수 승격은 변수 데이터 유형의 부호 비트에 따라 승격됩니다.
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0
두 가지 예를 들어라
int main()
{
char c1 = 3;
//首先要进行整型提升
//00000000000000000000000000000011
//00000011 - c1
char c2 = 127;
//首先要进行整型提升
//00000000000000000000000001111111
//01111111 - c2
char c3 = c1 + c2;
//00000000000000000000000000000011
//00000000000000000000000001111111
//00000000000000000000000010000010
// 这里要发生截断
//10000010 - c3
// 此时c1是字符型,但我们是要以整型形式打印,所以还要进行整型提升。
//11111111111111111111111110000010 补码
//11111111111111111111111110000001 反码
//10000000000000000000000001111110 原码
//-126
printf("%d\n", c3);//
return 0;
}
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;
}
예제에서 a와 b는 소성화 업그레이드가 필요하지만 c는 소성화 업그레이드가 필요하지 않습니다. b==0xb600은 거짓이지만 c는 발생하지 않는다. 정수를 개선하면 c==0xb6000000 식의 결과는 참이 된다.
프로그램의 결과 출력은 다음과 같다.
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}
c가 표현식 연산에 참여하는 한 소성 승격이 발생하고 +c 표현식이 승격되므로 sizeof(+c)는 4바이트입니다
. )는 4바이트이지만 sizeof(c)는 1바이트입니다.
12.2 산술 변환
연산자의 피연산자가 다른 유형인 경우 피연산자 중 하나가 다른 유형으로 변환되지 않으면 연산을 진행할 수 없습니다. 다음 계층 구조를 일반 산술 변환이라고 합니다.
long double
double
float
unsigned long int
long int
unsigned int
int피연산자의 유형이 위 목록에서 하위에 있는 경우 연산을 수행하기 전에 먼저 다른 피연산자의 유형으로 변환해야 합니다.
12.3 연산자의 속성
복잡한 표현식의 평가에 영향을 미치는 세 가지 요소가 있습니다.
1. 연산자의 우선순위(인접한 연산자여야 함)
2. 연산자의 결합성
3. 평가 순서 제어 여부.
인접한 두 연산자 중 어느 것이 먼저 실행됩니까? 우선 순위에 따라 다릅니다. 둘 다 동일한 우선 순위를 갖는 경우 연관성에 따라 달라집니다.
우리가 작성하는 표현식이 연산자의 속성을 통해 고유한 계산 경로를 결정할 수 없다면 이 표현식에 문제가 있는 것입니다
.
예를 들어 코드는 여러 컴파일 환경에서 다른 결과를 생성합니다.
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0;
}