สิ่งที่ไม่,
ดำเนินการทำใน 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
หรือint
s เราทำอย่างนี้:
*((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
เท่านั้น ผลลัพธ์ของ(
นิพจน์ ) is
1`
j
กรณีตามกฎความสำคัญที่แตกต่างกันตั้งแต่,
มีความสำคัญผู้ประกอบการต่ำสุด เพราะกฎเหล่านั้นคอมไพเลอร์เห็นมอบหมายแสดงออกคงที่อย่างต่อเนื่อง ... การแสดงออกที่มีการประเมินอีกครั้งในซ้ายไปขวาการสั่งซื้อและผลข้างเคียงของพวกเขาอยู่ที่มองเห็นจึงj
เป็นเป็นผลมาจาก5
j = 5
Interstingly, int j = 5,4,3,2,1;
ไม่ได้รับอนุญาตตามภาษาข้อมูลจำเพาะ initializerคาดว่าจะได้รับมอบหมายแสดงออกเพื่อให้ตรง,
ผู้ประกอบการไม่ได้รับอนุญาต
หวังว่านี่จะช่วยได้