Không những gì ,
nhà điều hành làm trong C?
Không những gì ,
nhà điều hành làm trong C?
Câu trả lời:
Cách diễn đạt:
(expression1, expression2)
Biểu thức đầu tiên được ước tính, sau đó biểu thức2 được ước tính và giá trị của biểu thức 2 được trả về cho toàn bộ biểu thức.
i
có các giá trị 5, 4, 3, 2 hoặc 1. Nó chỉ đơn giản là 0. Nó thực sự vô dụng trừ khi các biểu thức có tác dụng phụ.
i = b, c;
tương đương với (i = b), c
vì gán =
có độ ưu tiên cao hơn toán tử dấu phẩy ,
. Toán tử dấu phẩy có quyền ưu tiên thấp nhất trong tất cả.
expression1, expression2;
đầu tiên expression1
được đánh giá, có lẽ là do tác dụng phụ của nó (chẳng hạn như gọi hàm), sau đó có một điểm chuỗi, sau đó expression2
được đánh giá và giá trị trả về
Tôi đã thấy được sử dụng nhiều nhất trong while
các vòng lặp:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
Nó sẽ thực hiện thao tác, sau đó thực hiện kiểm tra dựa trên hiệu ứng phụ. Một cách khác là làm như thế này:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
while (read_string(s) && s.len() > 5)
. Rõ ràng là sẽ không hoạt động nếu read_string
không có giá trị trả về (hoặc không có giá trị có ý nghĩa). (Chỉnh sửa: Xin lỗi, không nhận thấy bài đăng này bao nhiêu tuổi.)
while (1)
với một break;
tuyên bố trong cơ thể. Cố gắng buộc phần đột phá của mã lên trong khi kiểm tra hoặc xuống kiểm tra do-while, thường gây lãng phí năng lượng và làm cho mã khó hiểu hơn.
while(1)
và break
;
Các nhà điều hành dấu phẩy sẽ đánh giá các toán hạng bên trái, loại bỏ kết quả và sau đó đánh giá các toán hạng phải và đó sẽ là kết quả. Việc sử dụng thành ngữ như được lưu ý trong liên kết là khi khởi tạo các biến được sử dụng trong một for
vòng lặp và nó đưa ra ví dụ sau:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
Mặt khác, không có nhiều ứng dụng tuyệt vời của toán tử dấu phẩy , mặc dù rất dễ lạm dụng để tạo mã khó đọc và duy trì.
Từ dự thảo tiêu chuẩn C99 , ngữ pháp như sau:
expression:
assignment-expression
expression , assignment-expression
và đoạn 2 nói:
Các toán hạng trái của một nhà điều hành dấu phẩy được đánh giá là một biểu thức còn thiếu; có một điểm trình tự sau khi đánh giá của nó. Sau đó toán hạng bên phải được đánh giá; kết quả có loại và giá trị của nó. 97) Nếu một nỗ lực được thực hiện để sửa đổi kết quả của toán tử dấu phẩy hoặc truy cập nó sau điểm chuỗi tiếp theo, hành vi không được xác định.
Chú thích 97 nói:
Một toán tử dấu phẩy không mang lại một giá trị .
có nghĩa là bạn không thể gán cho kết quả của toán tử dấu phẩy .
Điều quan trọng cần lưu ý là toán tử dấu phẩy có mức ưu tiên thấp nhất và do đó, có những trường hợp sử dụng ()
có thể tạo ra sự khác biệt lớn, ví dụ:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
sẽ có đầu ra sau:
1 4
Toán tử dấu phẩy kết hợp hai biểu thức hai bên của nó thành một, đánh giá cả hai theo thứ tự từ trái sang phải. Giá trị của phía bên phải được trả về là giá trị của toàn bộ biểu thức.
(expr1, expr2)
giống như { expr1; expr2; }
nhưng bạn có thể sử dụng kết quả củaexpr2
một lệnh gọi hoặc gán chức năng.
Nó thường được nhìn thấy trong for
các vòng lặp để khởi tạo hoặc duy trì nhiều biến như thế này:
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
Ngoài ra, tôi chỉ sử dụng nó "trong sự tức giận" trong một trường hợp khác, khi kết thúc hai thao tác phải luôn đi cùng nhau trong một macro. Chúng tôi đã có mã sao chép các giá trị nhị phân khác nhau vào bộ đệm byte để gửi trên mạng và một con trỏ được duy trì ở nơi chúng tôi đã có:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Trường hợp các giá trị là short
s hoặc int
s chúng tôi đã làm điều này:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Sau đó chúng tôi đọc rằng điều này không thực sự hợp lệ C, vì (short *)ptr
không còn là giá trị l và không thể tăng lên, mặc dù trình biên dịch của chúng tôi lúc đó không bận tâm. Để khắc phục điều này, chúng tôi chia biểu thức thành hai:
*(short *)ptr = short_value;
ptr += sizeof(short);
Tuy nhiên, cách tiếp cận này dựa vào tất cả các nhà phát triển ghi nhớ để đặt cả hai câu lệnh trong mọi thời điểm. Chúng tôi muốn một hàm nơi bạn có thể chuyển qua con trỏ đầu ra, giá trị và loại giá trị. Đây là C, không phải C ++ với các mẫu, chúng tôi không thể có một hàm tùy ý, vì vậy chúng tôi đã giải quyết trên một macro:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
Bằng cách sử dụng toán tử dấu phẩy, chúng tôi có thể sử dụng điều này trong các biểu thức hoặc như các câu lệnh như chúng tôi muốn:
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
Tôi không đề xuất bất kỳ ví dụ nào trong số này là phong cách tốt! Thật vậy, tôi dường như nhớ Mã hoàn thành của Steve McConnell khuyên không nên sử dụng các toán tử dấu phẩy trong một for
vòng lặp: để dễ đọc và duy trì, vòng lặp chỉ nên được điều khiển bởi một biến và các biểu thức trong for
dòng chỉ nên chứa mã kiểm soát vòng lặp, không phải các bit bổ sung khác của khởi tạo hoặc bảo trì vòng lặp.
Nó gây ra sự đánh giá của nhiều câu lệnh, nhưng chỉ sử dụng câu lệnh cuối cùng làm giá trị kết quả (giá trị, tôi nghĩ vậy).
Vì thế...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
nên kết quả là x được đặt thành 8.
Nơi duy nhất tôi thấy nó hữu ích là khi bạn viết một vòng lặp thú vị, nơi bạn muốn làm nhiều việc trong một trong các biểu thức (có thể là biểu thức init hoặc biểu thức vòng lặp.
bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
size_t i1, i2;
for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
{
if(a1[i1] != a2[i2])
{
return false;
}
}
return true;
}
Xin lỗi nếu có bất kỳ lỗi cú pháp nào hoặc nếu tôi trộn lẫn vào bất cứ điều gì không nghiêm ngặt C. Tôi không cho rằng, toán tử là hình thức tốt, nhưng đó là những gì bạn có thể sử dụng nó cho. Trong trường hợp trên có lẽ tôi sẽ sử dụng một while
vòng lặp để thay vào đó nhiều biểu thức trên init và loop sẽ rõ ràng hơn. (Và tôi sẽ khởi tạo i1 và i2 nội tuyến thay vì khai báo và sau đó khởi tạo .... blah blah blah.)
Tôi đang hồi sinh điều này chỉ đơn giản là để giải quyết các câu hỏi từ @Rajesh và @JeffMercado mà tôi nghĩ là rất quan trọng vì đây là một trong những công cụ tìm kiếm hàng đầu.
Lấy đoạn mã sau đây làm ví dụ
int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);
Nó sẽ in
1 5
Các i
trường hợp được xử lý như được giải thích bởi hầu hết các câu trả lời. Tất cả các biểu thức được đánh giá theo thứ tự từ trái sang phải nhưng chỉ biểu thức cuối cùng được gán cho i
. Kết quả của (
biểu thức )is
1`.
Các j
trường hợp theo các quy tắc ưu tiên khác nhau kể từ khi ,
có ưu tiên toán tử thấp nhất. Do những quy tắc, trình biên dịch thấy nhiệm vụ thể hiện, liên tục, liên tục ... . Các biểu thức một lần nữa được đánh giá theo thứ tự từ trái sang phải và do đó tác dụng phụ của chúng vẫn hiển thị, do đó, j
là 5
kết quả của j = 5
.
Xen kẽ, int j = 5,4,3,2,1;
không được cho phép bởi các đặc tả ngôn ngữ. Một trình khởi tạo mong đợi một biểu thức gán để một ,
toán tử trực tiếp không được phép.
Hi vọng điêu nay co ich.