2011-11-27 16 views
20

C, bir değişkeni kendi değerine sıfırlamak anlam ifade eder mi? Evet ise, ne için?Bir değişkeni kendi tanımsız değerine sıfırlayın

Detay vermeme izin verin. Git kaynaklarında, transport.c veya wt-status.c'da görüldüğü gibi, bir değişkeni kendi tanımsız değerine sıfırlamak için bazı örnekler vardır. Bu bildirimlerden ödevleri kaldırdım ve testleri çalıştırdım. Hiçbir regresyon görmedim, bu ödevlerin gereksiz olduğunu düşündüm.

Öte yandan, ben GCC 4.6 ve Clang 2.9 ile bazı basit testler yaptık. -Wall -std=c99 ve çeşitli -O seviyeleri ile derleniyor

#include <stdio.h> 
int main() { 
    printf("print to increase probability of registers being non-zero\n"); 
    int status = status; 
    return printf("%i\n", status); 
} 

hiçbir uyarı yazdırır ve status == 0 olduğunu göstermektedir. Sıfır olmayan bir optimizasyon seviyesiyle Clang, bazı çöp değerlerini yazdırır. Bu tür ifadelerin sonuçlarının tanımlanamayacağını anlamamı sağlıyor.

Böyle bir atamanın bir başlatılmamış değişken uyarısını engelleyebileceğini hayal edebiliyorum, ancak Git'ten alınan örnekler için geçerli değildir. Ödevleri kaldırmak herhangi bir uyarı getirmez.

Böyle atamalar tanımsız bir davranış mıdır? Eğer değilse, bunları ne için kullanıyorsunuz?


Git posta listesinde değişiklik önerdim. Here's what I've learned.

+0

Belki, gitmedeki örnekler * * sisteminiz için başlatılmamış bir değişken uyarısını, diğer geliştiricilerin düzenli olarak kullandığı sistemlerde bir uyarıyı bastırmaz. GCC ile, başlatılmamış değişken uyarıları optimizasyon bayraklarından etkilenir ve Clang, GCC için “bir ikame değiştirme” olmasına rağmen oldukça farklı uyarılar üretir. –

+1

Bu tür değişkenleri ilklendirmeyi tamamen bırakmak yerine 0 (veya -1) olarak başlatabilirim. Birisi kodu bir amaç için ekledi; Tuhaf kullanılan mekanizmayı bulsam da amacına saygı gösterebilirim. –

+1

@JonathanLeffler, sadece tuhaf değil, tuzak temsilcilikleri olan platformlarda bu tanımlanmamış bir davranış sağlar. –

cevap

11

Standart C99 §6.2.1/7 diyor bu da hazırlar çünkü:

bir yapı, sendika veya numaralandırma etiketi olmayan herhangi bir tanımlayıcı "sadece kendi Bildiricisi tamamlanmasından sonra başlar kapsamı vardır ." Declarator başlatıcı tarafından takip edilir.

Ancak status değeri Belirsiz olup. Ve anlamlı bir şeye başlatıldığından emin olamazsın.

Nasıl çalışır?
int status Değişkenin yığında (yerel depolama alanı) varlığını gösteren bir alan yaratır, bu daha sonra status = status gerçekleştirmek için okunur, status yığın çerçevesinde mevcut olan herhangi bir değere ilklendirilmiş olabilir.

Böyle bir kendi kendini başlatma durumuna karşı nasıl koruyabilirsiniz?
gcc öz başlatımlar tespit etmek ve hataları olarak bildirmek için belirli bir ortam sağlamaktadır:

-Werror kullanmamak =

Neden bu kodda kullanılan başlatılmamış -Winit-self?
Söz konusu kodda kullanıldığını düşünebilmemin tek nedeni, kullanılmayan değişken uyarısını ex için bastırmaktır: transport.c'da, denetim hiçbir zaman while döngüsünün içine girmiyorsa, o zaman cmp kontrol akışında kullanılmayacaktır. derleyici bunun için uyarı oluşturuyor olmalıdır. Aynı senaryo ben status = status (int status; göre) status değerini değiştirmez düşünüyorum wt-status.c

+2

Sanırım fikir, 'kullanılmamış değişken' uyarısını (kullanılmayan değişkenleri silerek daha basit bir şekilde yapabilirsiniz), ancak '(bazen) başlatılan uyarıdan önce kullanılan' (bazen) kullanılır. Bu küçük bir detay - cevabınızın ana kısmının geçerliliğini değiştirmez. –

+0

@JonathanLeffler: Yorumunuz birazda. Cevaplarımda biraz karışıklık var. –

1

Benim için bu tür bir otomatik atamanın başlatılmasının tek nedeni bir uyarıdan kaçınmaktır. o yararlıdır neden transport.c durumunda

, ben bile anlamıyorum. Başlatılmamış cmp bırakmış olurdum. (En azından C)

Kendi alışkanlık derleyici gereksiz başlatma optimize 0 genellikle, tüm değişkenlerin başlatılması ve başlatıldı tüm değişkenlerin sahip kolay ayıklama yapar. Bir değişken başlatılmamış kalmasını istediğiniz zaman

bir durum vardır ve bunu kendine atayabilirsiniz: rastgele tohumları: MacOS X 10.7.2 tarihinde

unsigned myseed = myseed; 
srand(myseed); 
+0

Ama hala başlatılmamış bayt tutarken 'cmp' okunduğunu fark edecek herhangi bir çalışma zamanı analiz araçları var mı? Mantık, 'cmp', 'while' öğesinde okunacak bir şeyi 'while' olarak adlandırmaya zorlamalıdır, böylece derleyicinin "ne yaptığını bildiği için kapatacağını" ancak "int cmp = 0" olur Çalışma zamanı analizini yen ve muhtemelen bir hatayı sakla. –

+0

Yani "compile-time * not * run-time * analysis ?? Ama senin yorumunu anlamıyorum. –

+0

'int cmp = cmp', derleyiciyi okunmadan önce her zaman atandığını düşünerek derleyiciyi kandırmak için yeterli olabilir, böylece derleme zamanı uyarıları bastırılır. Ancak, baytları çalışma zamanında izlerseniz, 'int cmp = cmp ',' while' döngüsünün durumu ilklendirilinceye kadar' cmp 'ı gereksiz yere bırakır; öyleyse, eğer mantık kusurlu ise ve 'if' 'cmp 'okuyabilmeden' while 'okuyabiliyorsa o zaman bir değer atayarak int int cmp = cmp kullanıldığında algılanabilir. 'Int cmp = 0 'kullanılması hem olası uyarıları bastırırdı. –

1

, bu örnek çalıştı - sonuçla gösterilen ...

$ cat x3.c 
#include <stdio.h> 

int status = -7; 

int main() 
{ 
    printf("status = %d\n", status); 
    int status = status; 
    printf("status = %d\n", status); 
    return 0; 
} 
$ make x3 
gcc -O -std=c99 -Wall -Wextra x3.c -o x3 
$ ./x3 
status = -7 
status = 1787486824 
$ 

main() yerel status böylece kendini başlatma kopyalar çöp etrafında printf() tarafından kullanılmıştır yığın alanı.

0

yılında status değişkenle gibi görünüyor. Ben unused variable uyarısını bastırmak için kullanılır düşünüyorum.