CFSDN nhấn mạnh vào việc tạo ra giá trị thông qua mã nguồn mở. Chúng tôi cam kết xây dựng một nền tảng chia sẻ tài nguyên để mọi người làm CNTT có thể tìm thấy thế giới tuyệt vời của riêng mình tại đây.
Bài viết blog CFSDN này giới thiệu cho bạn về ngôn ngữ C: các toán tử, được tác giả thu thập và sắp xếp. Nếu bạn quan tâm đến bài viết này, vui lòng thích nó.
Người điều hành
Phân loại
Toán tử số học.
Người điều khiển ca.
Toán tử bitwise.
Toán tử gán.
Toán tử một ngôi.
Toán tử quan hệ.
Toán tử logic.
Toán tử điều kiện.
Biểu thức dấu phẩy.
Tham chiếu chỉ số, lệnh gọi hàm và thành viên cấu trúc.
Toán tử số học
+ - * / %.
?
1
2
3
4
5
6
7
8
9
|
số nguyên
r = 9/2;
inf
(
"%d"
, trả về);
gấp đôi
ret2 = 9 / 2;
inf
(
"%lf"
, ret2);
gấp đôi
ret3 = 9 / 2,0;
inf
(
"%lf"
, ret3);
|
Từ hai phép so sánh này, ta có thể thấy rằng đây không phải là vấn đề lưu trữ mà 9/2 bằng 4 trong máy tính, do đó nó luôn bằng 4 bất kể được lưu trữ như thế nào.
Để có kết quả chính xác, hãy đổi thành 9.0/2 hoặc 9/2.0.
Khi cả hai toán hạng của / đều là số nguyên, phép chia số nguyên sẽ được thực hiện và phép chia dấu phẩy động sẽ được thực hiện miễn là có số dấu phẩy động. Cả hai toán hạng của % phải là số nguyên và kết quả nằm trong phạm vi [0, số chia−1] [0, số chia-1] [0, số chia−1].
Các toán tử dịch chuyển và toán tử bit sau đây phức tạp hơn và liên quan đến bit nhị phân.
Nhân viên điều hành ca
<< //Toán tử dịch chuyển trái>> //Toán tử dịch chuyển phải.
Quy tắc lưu trữ số nguyên
Toán tử dịch chuyển di chuyển các bit nhị phân. Các số nguyên được lưu trữ trong bộ nhớ dưới dạng bù 2 và phép toán dịch chuyển cũng là bù 2 trong bộ nhớ.
Lưu trữ số nguyên trong bộ nhớ:
- Số dương: ban đầu
- Mã này giống với mã bổ sung của một
- số âm:
- Mã gốc: chuỗi nhị phân
- Mã đảo ngược: bit dấu của mã gốc vẫn không thay đổi và các bit khác được đảo ngược từng bit một
- Mã bổ sung: Mã đảo ngược + 1
Quy tắc dịch chuyển trái-phải
Bây giờ chúng ta đã biết cách chuyển đổi bit nhị phân, hãy cùng xem xét các quy tắc di chuyển của toán tử dịch chuyển.
1. Toán tử dịch chuyển trái.
Bỏ phần bên trái và điền số 0 vào phần bên phải.

?
1
2
|
số nguyên
một = 5;
số nguyên
b = a << 1;
|
a<<1 nghĩa là phần bù của a được dịch chuyển một vị trí sang trái. Phần bù ban đầu của số dương là như nhau, do đó phần bù là 00000000 00000000 00000000 00000101. Dịch chuyển một vị trí sang trái, ta được 00000000 00000000 00000000 00001010, tức là 10 sau khi chuyển đổi.
Lúc này, giá trị của a vẫn là 5, có thể so sánh với b=a+1, và a sẽ không thay đổi.
?
1
2
|
số nguyên
c = -1;
số nguyên
d = c << 1;
|
Đầu tiên, hãy viết mã gốc của -1, sau đó lấy nghịch đảo của nó và thêm 1 để có được mã bổ sung, dịch chuyển mã bổ sung một vị trí sang trái, sau đó chuyển đổi mã bổ sung thu được thành mã gốc theo cùng quy tắc và bạn có thể nhận được -2.
10000000 00000000 00000000 00000001 - Mã gốc của -1 là 11111111 11111111 11111110 - Phần bù của -1 là 11111111 11111111 11111111 - Phần bù của -1.
11111111 11111111 11111111 11111110 - -1<
2. Toán tử dịch chuyển phải.
Có hai loại quy tắc dịch chuyển phải: dịch chuyển phải logic và dịch chuyển phải số học. Nhưng hầu hết các trình biên dịch đều sử dụng phép dịch chuyển phải số học.
Dịch chuyển phải số học: thêm bit dấu ban đầu ở bên trái và loại bỏ bit dấu bên phải.
Chuyển đổi logic sang phải: điền số 0 vào bên trái và bỏ số 0 vào bên phải.
?
1
2
3
4
5
6
|
số nguyên
một = -1;
inf
(
"%d\n"
, a >> 1);
|
Phép dịch chuyển logic sang phải sẽ chuyển đổi số âm thành số nguyên, do đó phép dịch chuyển số học sang phải sẽ chính xác hơn.
Điều đáng nói là phần bù của -1 vẫn là -1 sau khi dịch chuyển sang phải một vị trí.
Bổ sung:
Không khó để thấy rằng dịch chuyển sang trái làm cho dữ liệu lớn hơn, và dịch chuyển sang phải làm cho dữ liệu nhỏ hơn. Dịch chuyển sang trái có nghĩa là dữ liệu × 2 ×2 ×2, và dịch chuyển sang phải có nghĩa là dữ liệu ÷ 2 ÷2 ÷2. Các toán hạng dịch chuyển trái và dịch chuyển phải phải là số nguyên. Toán tử dịch chuyển không thể dịch chuyển các bit âm, tức là 1>>-1 và tiêu chuẩn không xác định hành vi.
Toán tử bitwise.
& // Phép toán AND từng bit | // Phép toán OR từng bit ^ // XOR từng bit.
Tương tự như vậy, các toán tử bitwise hoạt động trên các chữ số nhị phân.
Quy tắc hoạt động.
Phép toán bit AND & .
Nếu tất cả đều là 1 thì bằng 1; nếu có bất kỳ số 0 nào thì bằng 0.
Bitwise OR |
Nếu có 1 thì bằng 1; nếu tất cả đều bằng 0 thì bằng 0.
Loại trừ bit hoặc ^ .
Giống nhau là 0, khác nhau là 1.
Có thể thấy từ các quy tắc hoạt động rằng bitwise và bitwise hoặc và logic và và logic hoặc có bản chất tương tự nhau.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
số nguyên
một = 3;
số nguyên
b = -2;
số nguyên
c = a và b;
100000000 000000000 000000000 000000010 - -2 mã gốc
11111111 111111111 111111111 111111101 - nghịch đảo của -2
111111111 111111111 111111111 111111110 - -Bổ sung 2
000000000 000000000 000000000 0000000011 - Bộ đếm gốc giống hệt với 3!!
111111111 111111111 111111111 111111110 - -Bổ sung 2
000000000 000000000 000000000 0000000011 - Bổ sung 3
000000000 000000000 000000000 0000000010 - số bù hai của số!! (tất cả các số 1 đều là số 1 và bất kỳ số 0 nào cũng là số 0)
000000000 000000000 000000000 0000000010 - Bộ đếm ban đầu của số dương là giống nhau
|
Phương pháp tính toán.
- Tìm phần bù hai của hai toán hạng
- Tính toán kết quả của bitwise AND, OR, XOR
- Chuyển đổi mã bổ sung thu được thành mã ban đầu
Tính phần bù của a và b, sau đó thực hiện phép toán AND hoặc OR theo bit để có phần bù của số kết quả, rồi chuyển đổi thành mã ban đầu. Các bước này khá phức tạp nên đừng để bị mắc bẫy. Hai cái còn lại thì giống nhau ngoại trừ quy tắc vận hành khác nhau.
Để ý.
1. Phần bù gốc và phần bù ngược của số nguyên là giống nhau, do đó không áp dụng tiêu chuẩn cho số âm.
2. Kết quả của bitwise AND và bitwise OR cũng là mã bổ sung, cần phải được chuyển đổi thành mã gốc ở cuối.
ví dụ.
Không có biến tạm thời nào được tạo ra để trao đổi hai số.
?
1
2
3
4
5
6
7
8
9
|
số nguyên
một = 10;
số nguyên
b = 20;
inf
(
"a=%d,b=%d\n"
, a, b);
a = a + b;
b = a - b;
a = a - b;
inf
(
"a=%d,b=%d\n"
, a, b);
|
//2. a = a ^ b; b = a ^ b;//(a ^ b) ^ b = aa = a ^ b;//(a ^ b) ^ a = b //Khả năng đọc kém, chỉ hỗ trợ số dương.
Nếu giá trị của a^b được XOR với a, ta sẽ nhận được b; nếu giá trị của a^b được XOR với b, ta sẽ nhận được a. a ^ a = 0 a ^ 0 = a(a ^ a) ^ b = b (a ^ b) ^ a = b , do đó chúng ta cũng có thể nói rằng XOR hỗ trợ luật giao hoán
tính hữu ích.
Với một số nguyên dương, tôi phải làm gì nếu muốn biết bit thấp nhất của chữ số nhị phân (hoặc phần bù của nó nếu là số âm) là 0 hay 1?
Nếu kết quả là 1 thì bit thấp nhất là 1, nếu không thì là 0. giống:
?
1
2
3
4
5
|
số nguyên
một = 15;
số nguyên
b = a và 1;
00000000 00000000 00000000 00001111 - 15 Giống như bộ đếm ban đầu
00000000 00000000 00000000 000000001 - 1
00000000 00000000 00000000 00000001 - b=1 Giống như bộ đếm ban đầu
|
Từ ví dụ này, chúng ta có thể thấy rằng nếu thu được số dương &1, bit thấp nhất là 1 nếu kết quả là 1, nếu không thì là 0. Nếu kết hợp với toán tử dịch chuyển sang phải >>, bạn có thể lấy được từng chữ số. giống:
?
1
2
3
4
5
6
7
8
9
|
số nguyên
số = 15;
số nguyên
đếm = 0;
vì
(
số nguyên
tôi = 0; tôi < 32; tôi++)
{
nếu như
(((số >> i) & 1) == 1){
đếm++;
}
}
inf
(
"%d\n"
, đếm);
|
Toán tử gán
= //Toán tử gán hợp chất += -= *= /= %= >>= <<= .
Không có nhiều điều để nói về toán tử gán, vậy hãy cùng xem xét một điều hơi lạ một chút.
?
1
2
3
4
|
số nguyên
một = 10;
số nguyên
x = 0;
số nguyên
y = 20;
a = x = y+1;
|
Làm sao để hiểu được nhiệm vụ liên tục này?
Đầu tiên, y+1 được gán cho x, sau đó giá trị của biểu thức x=y+1 được gán cho a.
Toán tử một ngôi
! //Đảo ngược logic - //Âm + //Dương & //Lấy địa chỉ sizeof //Kiểu độ dài của toán hạng~ //Đảo ngược bit-- //Tiền tố và tiền tố—— ++ //Tiền tố và tiền tố++ * //Toán tử hủy tham chiếu (kiểu) //Chuyển đổi kiểu bắt buộc.
Phép đảo ngược logic.
Khác không là đúng, không là sai và cài đặt mặc định là !0=1.
Địa chỉ của nhà điều hành & Nhà điều hành Dereference*
?
1
2
3
4
|
số nguyên
một = 10;
số nguyên
* p = &a;
*p = 20;
inf
(
"%d\n"
, *P);
|
Địa chỉ của phần tử đầu tiên trong tên mảng.
?
1
2
3
4
5
6
7
|
số nguyên
mảng[10] = { 0 };
inf
(
"%p\n"
, sắp xếp + 1);
inf
(
"%p\n"
, &arr[0] + 1);
inf
(
"%p\n"
, &arr + 1);
|
arr và arr[0] đều là địa chỉ của phần tử đầu tiên, và &arr là địa chỉ của toàn bộ mảng. Chúng giống nhau khi in ra. Nhưng khi cả hai được cộng thêm 1, sự khác biệt sẽ xuất hiện. Hai số đầu tiên cộng với 1 là địa chỉ của phần tử thứ hai, trong khi &arr cộng với 1 bỏ qua địa chỉ của toàn bộ mảng.
Mở rộng ra một chút, *p đặt ở bên trái của = là một khoảng trắng, và đặt ở bên phải của = là một giá trị.
?
1
2
3
4
|
số nguyên
b = *p;
*p = b;
|
Bất kỳ biến nào cũng có thể được hiểu theo cách này. Đặt nó vào bên trái của = biểu diễn một khoảng trắng a = 10;, là giá trị bên trái. Đặt nó vào bên phải của = có nghĩa là giá trị p = a;, đây là giá trị đúng.
Toán tử chiều dài loại sizeof
sizeof tính toán kích thước của không gian bộ nhớ bị chiếm dụng bởi một biến hoặc kiểu dữ liệu, bất kể dữ liệu được lưu trữ trong bộ nhớ.
?
1
2
3
4
|
inf
(
"%d\n"
,
kích thước của
sắp xếp);
inf
(
"%d\n"
,
stren
(sắp xếp));
|
sizeof strlen() Sự khác biệt giữa hai giá trị này.
sizeof là toán tử tính toán không gian chiếm dụng và không quan tâm đến dữ liệu được lưu trữ. strlen() là hàm tính toán độ dài của chuỗi và tập trung vào số ký tự trước \0 trong dữ liệu được lưu trữ.
() sau sizeof là dấu ngoặc đơn của biểu thức, không phải toán tử gọi hàm. Vì sizeof là toán tử nên có thể bỏ qua.
ví dụ:
?
1
2
3
4
|
số nguyên
một = 5;
ngắn
s = 10;
inf
(
"%d\n"
,
kích thước của
(s = a + 2));
inf
(
"%d\n"
, s);
|
Khi gán dữ liệu int a+2 cho dữ liệu ngắn s, việc cắt bớt số nguyên sẽ xảy ra và dữ liệu vẫn là dữ liệu ngắn.
Biểu thức bên trong sizeof không tham gia vào phép tính, do đó s vẫn giữ nguyên như trước. Lý do: Phép tính bên trong sizeof được xử lý trong quá trình biên dịch trước và biểu thức bên trong đã được thay thế bằng một số trong quá trình thực thi chương trình.
Toán tử phủ định bitwise~
Đảo ngược tất cả các bit nhị phân.
ví dụ.
Làm thế nào để đổi một bit nhị phân từ 1 sang 0 và ngược lại?
?
1
2
3
4
5
6
7
8
9
10
11
|
số nguyên
một = 13;
số nguyên
b = a | (1<<1);
inf
(
"%d\n"
, b);
số nguyên
c = b & (~(1 << 1));
inf
(
"%d\n"
, c);
|
Nếu bit nhị phân là 0 và bạn muốn đổi nó thành 1, thì hãy thực hiện phép toán bitwise OR với một số như thế này... 00100... Nếu bit nhị phân là 1 và bạn muốn đổi nó thành 0, hãy thực hiện phép toán AND từng bit với số 11011..
++ -- Toán tử
Tiền tố ++ có nghĩa là sử dụng trước rồi sửa đổi sau, hậu tố ++ có nghĩa là sửa đổi trước rồi sử dụng sau.
?
1
2
3
4
5
6
|
số nguyên
một = 0;
inf
(
"%d\n"
, Một);
số nguyên
b = a++;
inf
(
"%d\n"
, b);
số nguyên
c = --a;
inf
(
"%d\n"
, c);
|
++ -- Cứ dùng như thế này thôi. Đừng theo đuổi những cách dùng vô ích và phức tạp. Sẽ chẳng có ai dùng theo cách đó đâu. Mục đích của việc viết code không phải là làm cho nó trở nên khó hiểu. giống:
?
1
2
|
số nguyên
một = 0;
số nguyên
b=(++a)+(a++)+(a++);
|
Mã như vậy sẽ tạo ra kết quả khác nhau trên các trình biên dịch khác nhau, do đó không cần phải tốn thời gian vào việc này.
Toán tử chuyển đổi kiểu (type)
?
1
|
số nguyên
một = (
số nguyên
)3.14;
|
ví dụ.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
vô hiệu
kiểm tra1(
số nguyên
mảng[]){
inf
(
"%d\n"
,
kích thước của
(sắp xếp));
}
vô hiệu
kiểm tra2(
char
ch[]){
inf
(
"%d\n"
,
kích thước của
(ch));
}
số nguyên
chủ yếu(){
số nguyên
mảng[10] = { 0 };
char
ch[10] = { 0 };
inf
(
"%d\n"
,
kích thước của
(sắp xếp));
inf
(
"%d\n"
,
kích thước của
(ch));
kiểm tra1(mảng);
kiểm tra2(ch);
trở lại
0;
}
|
(1) và (3) là tốt. Tên mảng được đặt riêng trong sizeof và kích thước của toàn bộ mảng được tính toán, lần lượt là 40 và 10. (2) và (4) là tên mảng được sử dụng làm tham số hàm. Mặc dù có vẻ như được nhận bằng một mảng, nhưng thực tế nó được nhận bằng một con trỏ và kích thước của con trỏ được sử dụng để tính toán. Khi tên mảng được sử dụng làm tham số hàm, không thể truyền toàn bộ mảng làm tham số. Trình biên dịch tự động hạ cấp nó thành con trỏ đến địa chỉ đầu tiên của phần tử.
Toán tử quan hệ =
> >= < <= != == .
== khác với =. Nếu bạn viết sai, nó sẽ trở thành một phép gán.
Toán tử logic
&& //Phép AND logic || //Phép OR logic.
Toán tử logic chỉ quan tâm đến sự thật hoặc sai. Logic AND && là AND, và logic OR || là OR.
Phép toán logic AND && yêu cầu cả hai toán hạng đều đúng để toàn bộ điều kiện là đúng, trong khi phép toán logic OR || chỉ yêu cầu một toán hạng đúng để toàn bộ điều kiện là đúng.
ví dụ.
?
1
2
3
4
5
6
7
8
|
số nguyên
chủ yếu()
{
số nguyên
tôi = 0, a = 0, b = 2, c = 3, d = 4;
tôi = a++ && ++b && d++;
tôi = a++||++b||d++;
inf
(
"a = %d\nb = %d\nc = %d\nd = %d\n"
, a, b, c, d);
trở lại
0;
}
|
Hoạt động ngắn mạch
1. Phép logic AND &&, khi biểu thức bên trái sai, toàn bộ điều kiện sai và không thực hiện thêm thao tác nào nữa.
2. Phép logic OR +, khi biểu thức bên trái là đúng, toàn bộ điều kiện là đúng và không thực hiện thêm phép tính nào nữa.
i = a++ && ++b && d++, bước đầu tiên a++=0 là sai, khi đó toàn bộ biểu thức là sai, i=0; i = a++||++b||d++, bước thứ hai a++ là đúng, toàn bộ biểu thức là đúng, các biểu thức sau không được tính toán.
Toán tử điều kiện
Nếu kết quả của biểu thức exp1 là đúng, exp2 được thực thi và kết quả của exp2 được sử dụng làm kết quả của toàn bộ biểu thức. Nếu không, exp3 được thực thi và gán cho toàn bộ biểu thức.
Biểu thức dấu phẩy
?
1
|
exp1, exp2, exp3,...,expn
|
Tính từ trái sang phải, kết quả của toàn bộ biểu thức chính là kết quả của biểu thức cuối cùng.
Trong trường hợp này, tại sao chúng ta cần phải tính toán biểu thức trước đó? Chúng ta không thể tính toán trực tiếp biểu thức cuối cùng sao?
Các biểu thức trước đó có thể ảnh hưởng đến giá trị của biểu thức cuối cùng. giống:
?
1
2
|
số nguyên
a = 1, b = 2;
số nguyên
c = (a>b, a=b+10, a, b=a+1);
|
Tham chiếu chỉ số, lệnh gọi hàm và thành viên cấu trúc
Toán tử tham chiếu chỉ số []

arr+i là địa chỉ của phần tử có chỉ số i trong mảng.
[] là một toán tử. Hai toán hạng của nó là tên mảng và chỉ số dưới, không thể thiếu bất kỳ toán hạng nào. Đối với arr[i], nó có thể được hiểu là *(arr+i), do đó chúng ta có thể viết:
?
1
|
mảng[i] <=> *(mảng+i) <=> *(i+mảng) <=> i[mảng]
|
?
1
2
3
4
|
số nguyên
mảng[10] = { 0 };
vì
(
số nguyên
tôi = 0; tôi < 10; tôi++){
inf
(
"%p --- %p\n"
, &i[arr], i+arr);
}
|
Điều này cho thấy [] là một toán tử và cú pháp này được hỗ trợ.
Toán tử gọi hàm ()
?
1
|
inf
(
"%u\n"
,
stren
(
"abc"
));
|
Ở đây, cả hai hàm printf và strlen đều phải được đặt trước bởi (), ngay cả khi không có tham số nào được truyền vào, nếu không thì sẽ sai.
Đối với lệnh gọi hàm toán tử (), có thể có một hoặc hai toán hạng.
Toán tử thành viên cấu trúc. ->
. Cấu trúc. Tên thành viên.
-> Con trỏ cấu trúc -> Tên thành viên.
Cấu trúc được sử dụng để mô tả một đối tượng phức tạp.
Định nghĩa cấu trúc
?
1
2
3
4
5
|
cấu trúc
sách{
char
tên[50];
char
định danh[15];
trôi nổi
giá;
};
|
Cấu trúc sử dụng
?
1
2
3
4
5
6
7
8
9
10
|
in(
cấu trúc
quyển b1){
inf
(
"Tên sách: %s\n"
, b1.tên);
inf
(
"Giá: %f\n"
, b1.giá);
inf
(
"Số sách: %s\n"
, b1.id);
}
số nguyên
chủ yếu(){
cấu trúc
quyển b1 = {
"Tan Haoqiang lập trình ngôn ngữ C"
,55,5 độ F,
"2020322222"
};
in(b1);
trở lại
0;
}
|
Sử dụng kiểu cấu trúc struct book, một biến kiểu cấu trúc b được tạo ra. Các thành viên của b bao gồm name, id và price.
Chúng ta cũng có thể sửa đổi giá sau này, chẳng hạn như:
Chúng tôi có thể thay đổi tiêu đề hoặc số sách không?
?
1
|
b1.tên =
"Cấu trúc dữ liệu"
;
|
Tất nhiên là không. Chúng ta có thể thấy cả tên sách và số ID của sách đều được tạo thông qua mảng. Đối với họ, b1.name là địa chỉ đầu tiên của mảng. Làm thế nào tôi có thể gán giá trị cho một địa chỉ?
Vì đây là một địa chỉ, chúng ta có thể hủy tham chiếu địa chỉ để truy cập các phần tử mảng. Hãy thử lại.
?
1
|
*(b1.tên) =
"Cấu trúc dữ liệu"
;
|
Tất nhiên, nó vẫn sai và sẽ hiển thị các ký tự không rõ ràng.
Còn các thành viên mảng của biến cấu trúc thì sao? Câu trả lời là sử dụng hàm thư viện strcpy để gán chuỗi.
?
1
|
chuỗi
(b1.tên,
"Cấu trúc dữ liệu"
);
|
Địa chỉ cấu trúc
Làm thế nào để sử dụng nó bằng cách truyền địa chỉ biến?
1.(*Con trỏ cấu trúc).Tên thành viên.
?
1
2
3
4
5
|
in2(
cấu trúc
sách*pb){
inf
(
"Tên sách: %s\n"
, (*pb).tên);
inf
(
"Giá: %f\n"
, (*pb).giá);
inf
(
"Số sách: %s\n"
, (*pb).id);
}
|
2.Con trỏ cấu trúc->tên thành viên.
?
1
2
3
4
5
|
in3(
cấu trúc
sách*pb){
inf
(
"Tên sách: %s\n"
, pb->tên);
inf
(
"Giá: %f\n"
, pb->giá);
inf
(
"Số sách: %s\n"
, pb->id);
}
|
Đánh giá biểu hiện
Khi một biểu thức được đánh giá, nó phụ thuộc một phần vào thứ tự ưu tiên và tính kết hợp của các toán tử và một phần vào các quy tắc riêng của trình biên dịch. Các biểu thức chúng ta viết phải làm cho logic của trình biên dịch nhất quán với logic mã của chúng ta, nếu không thì đó sẽ là mã vô dụng. Đồng thời, một số toán hạng trong một số biểu thức có thể yêu cầu nâng cấp kiểu.
Chuyển đổi kiểu ngầm định
Trong quá trình hoạt động, một số kiểu byte nhỏ sẽ được chuyển đổi thành kiểu byte lớn trước khi hoạt động và toàn bộ quá trình được trình biên dịch hoàn thành tự động cùng một lúc.
thăng cấp số nguyên
Ví dụ, short và char sẽ được chuyển đổi thành int trước khi tính toán. Điều này không có nghĩa là chuyển đổi kiểu chỉ xảy ra khi các kiểu dữ liệu khác nhau được vận hành, mà để thích ứng với toán tử 4 byte của CPU, tất cả dữ liệu sẽ được chuyển đổi thành số nguyên thông thường. Quá trình này được gọi là thăng cấp số nguyên. Việc thăng cấp số nguyên xảy ra bất cứ khi nào có tính toán. giống:
?
1
2
3
|
char
a=1,b=2,c=3;
...
char
d=a+b+c;
|
Ví dụ, trước tiên hãy nâng cấp kiểu ký tự a, b, c thành số nguyên thông thường, sau đó thực hiện phép toán, đưa chúng vào d và cuối cùng cắt bớt chúng, chỉ lấy byte cuối cùng và chuyển đổi chúng trở lại kiểu ký tự.
Làm thế nào để cải thiện ngoại hình của bạn
Các chương trình khuyến mại tích phân được thực hiện theo bit dấu của loại. giống:
?
1
2
3
4
5
|
char
c = -1;
inf
(
"%d\n"
,c);
|
Số có dấu
Viết ra phần bù nhị phân của biến, điền vào đó bit có dấu cao nhất, sau đó chuyển đổi thành mã gốc
Số không dấu
Bit cao nhất được điền bằng 0.
Làm thế nào để có được phần bù của c? (1) Đầu tiên xử lý c như một kiểu int và sau đó viết phần bù hai 32 bit. (2) Sau đó cắt bớt nó để chỉ lấy 8 bit cuối cùng. (3) Cuối cùng, điền bit cao nhất bằng 0 nếu nó bằng 0, nếu không thì điền nó bằng 1.
ví dụ.
Ví dụ 1 .
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
char
một = 3;
char
b = 127;
char
c = a + b;
inf
(
"%d\n"
, c);
|
Viết ra phần bù 32 bit của a và b, cắt bớt, lưu vào bộ nhớ, thực hiện thăng hạng số nguyên, điền vào bit cao nhất, thực hiện tính toán, cắt bớt, sau đó thực hiện thăng hạng số nguyên để chuyển đổi phần bù thu được trở lại mã gốc
giống:

Sau khi có được mã nhị phân của hai biến, chúng ta thực hiện thăng cấp số nguyên trên chúng và sau đó cắt bớt kết quả vì chúng cần được lưu trữ trong biến ký tự c. Vì biến c được in dưới dạng %d, nên mã bù 2 bị cắt bớt (tất cả các mã bù 2 được lưu trữ trong bộ nhớ) lại được nâng cấp thành mã gốc.
Ví dụ 2 .
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
hai mươi mốt
hai mươi hai
|
char
a = 0xb6;
ngắn
b = 0xb600;
số nguyên
c = 0xb6000000;
nếu như
(a == 0xb6)
inf
(
"Một"
);
nếu như
(b == 0xb600)
inf
(
"b"
);
nếu như
(c == 0xb60000)
inf
(
"c"
);
|
Đầu tiên, ta viết số bù 2 của a, b và c (tất cả đều là số dương). Sau đó tôi phát hiện ra rằng có một phép toán (== cũng là một phép toán). Chỉ cần có phép toán, số nguyên phải được thăng cấp. Sau khi số nguyên được thăng cấp, bit cao nhất là 1 và theo mặc định là số âm. Theo cách này, sau khi chuyển đổi ngược lại ban đầu, nó sẽ luôn là một số âm và không bằng 0xb6 và 0xb600. Chỉ có c là số nguyên mặc định và không cần phải được thăng cấp.
Ví dụ 3 .
?
1
2
3
4
|
char
c = 1;
inf
(
"%u\n"
,
kích thước của
(c));
inf
(
"%u\n"
,
kích thước của
(+c));
inf
(
"%u\n"
,
kích thước của
(-c));
|
Khi tính sizeof(c), không có phép toán nào được thực hiện nên không xảy ra quá trình thăng tiến tích phân. Toán tử dương và toán tử âm cũng là toán tử. Khi sizeof(±c), hai biểu thức (+c) và (-c) được nâng cấp thành số nguyên, do đó chúng trở thành bốn byte.
Chuyển đổi số học
Đối với short và char, số nguyên cần được nâng cấp thành int, nhưng còn số thực và số nguyên dài thì sao? Đối với các loại này, nó không được gọi là thăng cấp số nguyên mà là chuyển đổi số học.

Thứ tự từ cao đến thấp. Khi một loại có độ chính xác thấp được vận hành với một loại có độ chính xác cao, độ chính xác thấp sẽ được chuyển đổi thành độ chính xác cao, sau đó thao tác sẽ được thực hiện với dữ liệu có độ chính xác cao. ví dụ:
?
1
2
3
4
|
số nguyên
một = 4;
trôi nổi
f = 4,5f;
f = a + f;
inf
(
"%f\n"
, f);
|
Khi tính toán f, trước tiên bạn cần chuyển đổi a thành kiểu số dấu phẩy động có độ chính xác đơn.
Thuộc tính của toán tử
Có ba yếu tố ảnh hưởng đến việc đánh giá một biểu thức:
- Quyền ưu tiên của toán tử
- Tính kết hợp của các toán tử
- Có nên kiểm soát thứ tự đánh giá không
Trong hai toán tử liền kề, toán tử nào sẽ được thực hiện trước?
Trước tiên hãy xem xét mức độ ưu tiên, nếu các mức độ ưu tiên giống nhau, hãy xem xét tính kết hợp.
?
1
2
3
4
5
6
7
|
a*b+c*d+e*f;
c + --c;
số nguyên
một = 1;
a=(++i)+(++i)+(++i);
|

Những biểu thức như vậy sẽ tạo ra những kết quả khác nhau ở những trình biên dịch khác nhau vì tiêu chuẩn của mỗi trình biên dịch là khác nhau.
Đối với các biểu thức như vậy, chúng ta biết thứ tự ưu tiên và tính kết hợp của các toán tử, nhưng chúng ta vẫn không thể xác định được đường dẫn duy nhất để tính toán biểu thức, do đó, mã như vậy là không tốt. Tốt hơn là viết thêm một vài bước để xác định đường dẫn thực thi duy nhất của biểu thức theo cách chuẩn hóa, thay vì theo đuổi sự đơn giản quá mức, đó không phải là mục đích của mã.
Tóm tắt
Nếu biểu thức chúng ta viết không thể xác định đường dẫn tính toán duy nhất thông qua các thuộc tính của toán tử thì biểu thức có vấn đề.
Đây là phần kết của bài viết này. Tôi hy vọng nó có thể hữu ích với bạn. Tôi cũng hy vọng bạn có thể chú ý nhiều hơn đến nhiều nội dung khác của tôi! .
Liên kết gốc: https://blog.csdn.net/yourfriendyo/article/details/119257734.
Cuối cùng, bài viết này về một bài viết giới thiệu cho bạn về ngôn ngữ C: toán tử kết thúc tại đây. Nếu bạn muốn biết thêm về một bài viết giới thiệu cho bạn về ngôn ngữ C: toán tử, vui lòng tìm kiếm các bài viết trên CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!