สิ่งที่ไม่,ดำเนินการทำใน C?
สิ่งที่ไม่,ดำเนินการทำใน C?
คำตอบ:
การแสดงออก:
(expression1, expression2)
นิพจน์แรก 1 ถูกประเมินจากนั้นนิพจน์ 2 จะถูกประเมินค่าและส่งกลับค่าของนิพจน์ 2 สำหรับนิพจน์ทั้งหมด
iมีค่า 5, 4, 3, 2 หรือ 1 มันเป็นเพียง 0 มันไม่มีประโยชน์จริงยกเว้นว่าการแสดงออกมีผลข้างเคียง
i = b, c;เทียบเท่ากับ(i = b), cเพราะเนื่องจากได้รับมอบหมายมีความสำคัญสูงกว่าผู้ประกอบการจุลภาค= ,ตัวดำเนินการเครื่องหมายจุลภาคมีลำดับความสำคัญต่ำสุดของทั้งหมด
expression1, expression2;ครั้งแรกน่าexpression1จะเป็นผลข้างเคียงของมัน (เช่นการเรียกใช้ฟังก์ชั่น) จากนั้นก็มีจุดลำดับจากนั้นexpression2จะมีการประเมินและมูลค่ากลับมา ...
ฉันเคยเห็นใช้มากที่สุดในwhileลูป:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
มันจะทำการดำเนินการจากนั้นทำการทดสอบตามผลข้างเคียง วิธีอื่นจะทำเช่นนี้:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
while (read_string(s) && s.len() > 5). เห็นได้ชัดว่าจะไม่ทำงานหากread_stringไม่มีค่าตอบแทน (หรือไม่มีค่าที่มีความหมาย) (แก้ไข: ขออภัยไม่ได้สังเกตว่าโพสต์นี้เก่าแล้ว)
while (1)กับbreak;ข้อความในร่างกาย การพยายามบังคับให้ส่วนที่แบ่งออกของรหัสเข้าสู่การทดสอบในขณะที่หรือลงในการทดสอบแบบทำในขณะที่มักจะเสียพลังงานและทำให้รหัสยากที่จะเข้าใจ
while(1)และbreak;
ประกอบจุลภาคจะประเมินตัวถูกดำเนินการทางด้านซ้ายทิ้งผลและประเมินตัวถูกดำเนินการที่เหมาะสมและที่จะเป็นผล การใช้สำนวนตามที่ระบุไว้ในลิงค์คือเมื่อเริ่มต้นตัวแปรที่ใช้ในforวงและมันให้ตัวอย่างต่อไปนี้:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
มิฉะนั้นจะไม่มีการใช้งานที่ยอดเยี่ยมมากมายของโอเปอเรเตอร์คอมม่าแม้ว่าจะเป็นการง่ายในการสร้างโค้ดที่อ่านและบำรุงรักษาได้ยาก
จากมาตรฐาน C99 ฉบับร่างไวยากรณ์จะเป็นดังนี้:
expression:
assignment-expression
expression , assignment-expression
และวรรค 2พูดว่า:
ถูกดำเนินการทางด้านซ้ายของผู้ประกอบการจุลภาคได้รับการประเมินเป็นนิพจน์โมฆะ; มีจุดลำดับหลังจากการประเมิน จากนั้นจะทำการประเมินตัวถูกดำเนินการที่เหมาะสม ผลลัพธ์มีประเภทและค่าของมัน 97)หากมีความพยายามในการปรับเปลี่ยนผลการดำเนินงานของเครื่องหมายจุลภาคหรือเข้าถึงได้หลังจากจุดลำดับถัดไปพฤติกรรมจะไม่ได้กำหนด
Footnote 97พูดว่า:
ผู้ประกอบการจุลภาคไม่ได้ผลผลิต lvalue
ซึ่งหมายความว่าคุณไม่สามารถกำหนดให้กับผลจากการที่ผู้ประกอบการจุลภาค
สิ่งสำคัญคือให้สังเกตว่าโอเปอเรเตอร์จุลภาคมีลำดับความสำคัญต่ำสุดและดังนั้นจึงมีกรณีที่การใช้()สามารถสร้างความแตกต่างใหญ่เช่น:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
จะมีผลลัพธ์ต่อไปนี้:
1 4
ตัวดำเนินการเครื่องหมายจุลภาครวมสองนิพจน์ทั้งสองข้างไว้ในที่เดียวโดยประเมินทั้งคู่ตามลำดับจากซ้ายไปขวา ค่าของด้านขวาถูกส่งคืนเป็นค่าของนิพจน์ทั้งหมด
(expr1, expr2)เป็นเหมือน{ expr1; expr2; }แต่คุณสามารถใช้ผลลัพธ์ของexpr2การโทรหรือการกำหนดฟังก์ชัน
มันมักจะเห็นในforลูปเพื่อเริ่มต้นหรือรักษาหลายตัวแปรเช่นนี้
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 */
}
นอกเหนือจากนี้ฉันเพิ่งใช้มัน "ด้วยความโกรธ" ในอีกกรณีหนึ่งเมื่อรวมการดำเนินการสองอย่างที่ควรรวมเข้าด้วยกันเป็นแมโคร เรามีรหัสที่คัดลอกค่าไบนารีต่าง ๆ ลงในบัฟเฟอร์ไบต์สำหรับส่งบนเครือข่ายและตัวชี้ยังคงอยู่ซึ่งเราได้รับ:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
ไหนค่าได้shortหรือints เราทำอย่างนี้:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
ต่อมาเราอ่านว่านี่ไม่ถูกต้อง C จริง ๆ เพราะ(short *)ptrไม่มีค่า l อีกต่อไปและไม่สามารถเพิ่มขึ้นได้แม้ว่าคอมไพเลอร์ของเราในเวลานั้นไม่สนใจ ในการแก้ไขปัญหานี้เราแบ่งนิพจน์เป็นสองส่วน:
*(short *)ptr = short_value;
ptr += sizeof(short);
อย่างไรก็ตามวิธีนี้อาศัยนักพัฒนาทั้งหมดที่จำว่าต้องใส่ทั้งสองข้อความไว้ตลอดเวลา เราต้องการฟังก์ชั่นที่คุณสามารถส่งผ่านตัวชี้ออกค่าและประเภทของค่า นี่คือ C ไม่ใช่ C ++ กับเทมเพลตเราไม่สามารถใช้ฟังก์ชั่นใดก็ได้ดังนั้นเราจึงตัดสินด้วยแมโคร:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
ด้วยการใช้ตัวดำเนินการคอมม่าเราสามารถใช้สิ่งนี้ในการแสดงออกหรือเป็นคำสั่งตามที่เราต้องการ:
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));
ฉันไม่ได้แนะนำตัวอย่างใด ๆ เหล่านี้ว่าเป็นสไตล์ที่ดี! อันที่จริงฉันดูเหมือนจะจำรหัสที่สมบูรณ์ของ Steve McConnell เพื่อให้คำแนะนำแม้กระทั่งการใช้เครื่องหมายคอมม่าในforลูป: เพื่อความสะดวกในการอ่านและการบำรุงรักษาลูปควรถูกควบคุมโดยตัวแปรเพียงตัวเดียวเท่านั้นและนิพจน์ในforบรรทัดนั้น ไม่ใช่บิตพิเศษอื่น ๆ ของการเริ่มต้นหรือการบำรุงรักษาลูป
มันทำให้การประเมินผลของหลายงบ แต่ใช้เพียงหนึ่งล่าสุดเป็นค่าผลลัพธ์ (rvalue ฉันคิดว่า)
ดังนั้น...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
ควรส่งผลให้ x ถูกตั้งค่าเป็น 8
ตามที่คำตอบก่อนหน้านี้ได้ระบุไว้มันจะประเมินข้อความทั้งหมด แต่ใช้คำสุดท้ายเป็นค่าของการแสดงออก โดยส่วนตัวฉันพบเพียงว่ามันมีประโยชน์ในการวนซ้ำนิพจน์:
for (tmp=0, i = MAX; i > 0; i--)
ที่เดียวที่ฉันเห็นว่ามันมีประโยชน์คือเมื่อคุณเขียนลูปขี้ขลาดที่คุณต้องการทำหลายสิ่งในนิพจน์ (อาจเป็นนิพจน์ init หรือนิพจน์แบบวนซ้ำสิ่งที่ชอบ:
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;
}
ให้อภัยฉันหากมีข้อผิดพลาดทางไวยากรณ์หรือถ้าฉันผสมในสิ่งที่ไม่เข้มงวด C. ฉันไม่เถียงว่าตัวดำเนินการเป็นรูปแบบที่ดี แต่นั่นคือสิ่งที่คุณสามารถใช้เพื่อ ในกรณีข้างต้นฉันอาจใช้การwhileวนซ้ำแทนดังนั้นการแสดงออกหลายครั้งในการเริ่มต้นและการวนซ้ำจะชัดเจนมากขึ้น (และฉันจะเริ่มต้น i1 และ i2 แบบอินไลน์แทนการประกาศแล้วเริ่มต้น .... blah blah blah.)
ฉันขอคืนสิ่งนี้เพื่อตอบคำถามจาก @Rajesh และ @JeffMercado ซึ่งฉันคิดว่ามีความสำคัญมากเนื่องจากนี่เป็นหนึ่งในโปรแกรมค้นหายอดนิยม
ยกตัวอย่างโค้ดต่อไปนี้
int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);
มันจะพิมพ์
1 5
iกรณีที่มีการจัดการตามที่อธิบายไว้โดยคำตอบมากที่สุด นิพจน์ทั้งหมดจะได้รับการประเมินตามลำดับจากซ้ายไปขวา แต่จะกำหนดเฉพาะรายการสุดท้ายiเท่านั้น ผลลัพธ์ของ( นิพจน์ ) is1`
jกรณีตามกฎความสำคัญที่แตกต่างกันตั้งแต่,มีความสำคัญผู้ประกอบการต่ำสุด เพราะกฎเหล่านั้นคอมไพเลอร์เห็นมอบหมายแสดงออกคงที่อย่างต่อเนื่อง ... การแสดงออกที่มีการประเมินอีกครั้งในซ้ายไปขวาการสั่งซื้อและผลข้างเคียงของพวกเขาอยู่ที่มองเห็นจึงjเป็นเป็นผลมาจาก5j = 5
Interstingly, int j = 5,4,3,2,1;ไม่ได้รับอนุญาตตามภาษาข้อมูลจำเพาะ initializerคาดว่าจะได้รับมอบหมายแสดงออกเพื่อให้ตรง,ผู้ประกอบการไม่ได้รับอนุญาต
หวังว่านี่จะช่วยได้