,
Operatör C'de ne yapar ?
,
Operatör C'de ne yapar ?
Yanıtlar:
İfade:
(expression1, expression2)
İlk ifade1 değerlendirilir, daha sonra ifade2 değerlendirilir ve tüm ifade için ifade2 değeri döndürülür.
i
5, 4, 3, 2 veya 1 değerlerine sahip olmayacaktır. Basitçe 0'dır. İfadelerin yan etkileri olmadığı sürece pratik olarak işe yaramaz.
i = b, c;
eşdeğerdir (i = b), c
atama nedeniyle nedeniyle =
virgül operatörü daha yüksek önceliğe sahiptir ,
. Virgül operatörü en düşük önceliğe sahiptir.
expression1, expression2;
ilk expression1
olarak, muhtemelen yan etkileri (bir işlevi çağırmak gibi) expression2
için değerlendirilir , daha sonra bir dizi noktası vardır, daha sonra değerlendirilir ve değer döndürülür ...
En çok while
döngülerde kullanıldığını gördüm :
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
İşlemi yapacak, sonra yan etkiye dayalı bir test yapacaktır. Diğer yol bunu böyle yapmak olurdu:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
while (read_string(s) && s.len() > 5)
. Açıkçası read_string
bir dönüş değeri yoksa (veya anlamlı bir değeri yoksa) bu işe yaramaz . (Düzenle: Üzgünüz, bu
while (1)
bir break;
ifadeyle kullanmaktan korkmayın . Kodun kırılma kısmını while testine veya down-while testine zorlamaya çalışmak genellikle enerji israfıdır ve kodun anlaşılmasını zorlaştırır.
while(1)
ve break
;
Virgül operatörü sol işlenen değerlendirecek, sonuç atmak ve sonra sağ işlenen değerlendirir ve o sonuç olacaktır. Bağlantıda belirtildiği gibi deyimsel kullanım, bir for
döngüde kullanılan değişkenlerin başlatılmasıdır ve aşağıdaki örneği verir:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
Aksi takdirde değil çok var harika kullanımları virgül operatörü okumak ve korumak zor kodu oluşturmak üzere kötüye kolay olmasına rağmen,.
Gönderen taslak C99 standardında aşağıdaki gibi dilbilgisi geçerli:
expression:
assignment-expression
expression , assignment-expression
ve paragraf 2 diyor ki:
Virgülle operatör sol işlenen bir boşluk ifadesi olarak değerlendirilir; değerlendirilmesinden sonra bir sıralama noktası vardır. Sonra doğru işlenen değerlendirilir; sonucun türü ve değeri vardır. 97) Bir virgül operatörünün sonucunu değiştirme veya bir sonraki sıra noktasından sonra erişme girişiminde bulunulursa, davranış tanımsızdır.
Dipnot 97 diyor ki:
Bir virgül operatörü etmez bir lvalue vermeyecektir .
Bu, virgül operatörünün sonucuna atayamayacağınız anlamına gelir .
Virgül operatörünün en düşük önceliğe sahip olduğunu ve bu nedenle kullanımın ()
büyük bir fark yaratabileceği durumlar olduğunu belirtmek önemlidir , örneğin:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
aşağıdaki çıktıya sahip olacaktır:
1 4
Virgül operatörü, iki ifadeyi her iki tarafı da bir araya getirir ve her ikisini de soldan sağa doğru değerlendirir. Sağ tarafın değeri, tüm ifadenin değeri olarak döndürülür.
(expr1, expr2)
gibidir { expr1; expr2; }
ancak sonucunu expr2
bir işlev çağrısında veya atamada kullanabilirsiniz.
Genellikle for
döngülerde, bunun gibi birden çok değişkeni başlatmak veya korumak için görülür :
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 */
}
Bunun dışında, her zaman bir makroda bir araya gelmesi gereken iki işlemi tamamlarken, sadece başka bir durumda "öfkeyle" kullandım. Bir ağda göndermek için çeşitli ikili değerleri bir bayt arabelleğine kopyalayan kodumuz vardı ve bir işaretçi, ulaştığımız yerde korunuyordu:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Değerler short
s veya int
s olduğunda bunu yaptık:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Daha sonra bunun gerçekten geçerli bir C olmadığını okuduk, çünkü (short *)ptr
o zamanlar derleyici umursamamasına rağmen artık bir l değeri değil ve artırılamıyor. Bunu düzeltmek için ifadeyi ikiye ayırdık:
*(short *)ptr = short_value;
ptr += sizeof(short);
Bununla birlikte, bu yaklaşım her iki ifadeyi de her zaman koymayı hatırlayan tüm geliştiricilere dayanıyordu. Çıktı işaretçisini, değeri ve değerin türünü iletebileceğiniz bir işlev istedik. Bu şablonlarla C ++ değil, keyfi bir tür almak için bir fonksiyonumuz olamazdı, bu yüzden bir makroya yerleştik:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
Virgül operatörünü kullanarak bunu ifadelerde veya istediğimiz gibi ifadelerde kullanabildik:
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));
Bu örneklerden herhangi birinin iyi bir stil olduğunu önermiyorum! Nitekim, Steve McConnell hatırlamak görünüyor Kod tamamlayın bile virgülle operatörleri kullanarak karşı danışmanlık for
döngü: okunabilmesi ve bakımı için, döngü yalnızca bir değişken tarafından kontrol edilmelidir ve ifadeler for
kendisi sadece döngü kontrol kodu içermelidir hattı, diğer başlatma veya döngü bakım bitleri değil.
Birden çok ifadenin değerlendirilmesine neden olur, ancak sonuç olarak sadece sonuncuyu kullanır (değer, bence).
Yani...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
x değeri 8 olarak ayarlanmalıdır.
Yararlı olduğunu gördüğüm tek yer, ifadelerden birinde (muhtemelen init ifadesi veya döngü ifadesi) birden çok şey yapmak istediğiniz bir funky döngü yazmanızdır.
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;
}
Herhangi bir sözdizimi hatası varsa veya katı C olmayan bir şeyle karışırsam affedersiniz, operatörün iyi bir form olduğunu iddia etmiyorum, ama bunun için kullanabilirsiniz. Yukarıdaki durumda, while
bunun yerine muhtemelen bir döngü kullanacağım, böylece init ve loop üzerindeki çoklu ifadeler daha açık olacaktır. (Ve ben i1 ve i2 satır içi bildirmek ve sonra başlatmak yerine .... başlatmak filan filan filan.)
@Rajesh ve @JeffMercado'dan gelen soruları ele almak için bunu canlandırıyorum, çünkü bu en iyi arama motoru hitlerinden biri.
Örneğin aşağıdaki kod snippet'ini ele alalım
int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);
Yazdırılacak
1 5
i
En cevapları tarafından açıklandığı gibi durum ele alınır. Tüm ifadeler soldan sağa sırada değerlendirilir, ancak yalnızca sonuncusu atanır i
. (
İfadenin sonucu ) is
1`.
j
Çünkü durum farklı öncelik kuralları aşağıdaki ,
en düşük operatör önceliği vardır. Bu kurallar nedeniyle derleyici atama-ifade, sabit, sabit ... görür . İfadeleri tekrar düzene-sağ-sol ve bunların yan etkileri görülebilir kalmak nedenle değerlendirilir j
olduğu 5
bir sonucu olarak j = 5
.
Interstingly, int j = 5,4,3,2,1;
dil spec tarafından izin verilmiyor. Bir başlatıcı atama ifadesini bekler, böylece doğrudan bir ,
operatöre izin verilmez.
Bu yardımcı olur umarım.