it-swarm-tr.com

C de yeni değişkenleri nerede ilan edebilir ve beyan edemezsiniz?

Programın/fonksiyonun üstündeki tüm değişkenleri açıklamak gerektiğini ve ifadeler arasında yenilerini açıklamanın sorunlara yol açabileceğini duydum (muhtemelen bir öğretmenden).

Ama sonra K&R okuyordum ve şu cümleyi okudum: "Değişkenlerin bildirimleri (ilklendirmeler dahil), yalnızca bir işlevi başlatan herhangi bir bileşik ifadeyi tanıtan sol küme izini takip edebilir". Bir örnek ile takip eder: 

if (n > 0){
    int i;
    for (i=0;i<n;i++)
    ...
}

Konsept ile biraz oynadım ve dizilerde bile çalışıyor. Örneğin: 

int main(){
    int x = 0 ;

    while (x<10){
        if (x>5){
            int y[x];
            y[0] = 10;
            printf("%d %d\n",y[0],y[4]);
        }
        x++;
    }
}

Peki tam olarak ne zaman değişkenleri bildirmeme izin verilmiyor? Örneğin, değişken açıklamam açılış açılışından hemen sonra değilse ne olur? Burası gibi:

int main(){
    int x = 10;

    x++;
    printf("%d\n",x);

    int z = 6;
    printf("%d\n",z);
}

Bu, programa/makineye bağlı olarak sorunlara neden olabilir mi? 

68
Daniel Scocco

Ayrıca, sık sık fonksiyonun en üstündeki değişkenleri koymanın işleri yapmanın en iyi yolu olduğunu da duyuyorum, ancak kesinlikle katılmıyorum. Değişkenleri mümkün olan en küçük kapsamla sınırlandırmayı tercih ediyorum, bu yüzden kötüye kullanma şansları daha az ve böylece programdaki her satırdaki zihinsel alanımı dolduran şeyler daha az.

C'nin tüm sürümleri sözcüksel blok kapsamına izin verirken, değişkenleri bildirebileceğiniz yer, hedeflediğiniz C standardının sürümüne bağlıdır:

C99 veya C++

Gcc ve clang gibi modern C derleyicileri, C99 ve C11 standartlarını destekler; Değişkenin kapsamı bildirim noktasından bloğun sonuna kadar başlar (bir sonraki kapanış ayracı).

if( x < 10 ){
   printf("%d", 17);  // z is not in scope in this line
   int z = 42;
   printf("%d", z);   // z is in scope in this line
}

Ayrıca döngü başlatıcıları için içindeki değişkenleri de beyan edebilirsiniz. Değişken sadece döngü içinde var olacaktır.

for(int i=0; i<10; i++){
    printf("%d", i);
}

ANSI C (C90)

Eski ANSI C standardını hedefliyorsanız, bir açılış ayracından hemen sonra değişkenleri bildirmekle sınırlandırılırsınız.1.

Bu, tüm değişkenlerinizi işlevlerinizin başında bildirmeniz gerektiği anlamına gelmez. C'de bir ifadenin gidebileceği herhangi bir yere bir ayraçla ayrılmış bir blok koyabilirsiniz (yalnızca if veya for gibi şeylerden sonra değil) ve bunu yeni değişken kapsamları sunmak için kullanabilirsiniz. Aşağıdaki, önceki C99 örneklerinin ANSI C versiyonudur:

if( x < 10 ){
   printf("%d", 17);  // z is not in scope in this line

   {
       int z = 42;
       printf("%d", z);   // z is in scope in this line
   }
}

{int i; for(i=0; i<10; i++){
    printf("%d", i);
}}

1 Gcc kullanıyorsanız, gerçekten C90 standardını uygulamak ve değişkenlerin yanlış yerde bildirildiğinden şikayet etmek için --pedantic bayrağını geçmeniz gerektiğini unutmayın. Eğer sadece -std=c90 kullanırsanız, gcc'nin daha esnek C99 değişken bildirimlerine de izin veren bir C90 süpersetini kabul etmesini sağlar.

106
hugomg

missingno, ANSI C'nin izin verdiği şeyleri kapsamamaktadır, ancak öğretmenlerinizin neden değişkenlerinizi işlevlerinizin üstünde açıkladığınızı söylemesini istememektedir. Değişkenleri tek sayılı yerlerde bildirmek, kodunuzun okunmasını zorlaştırabilir ve bu, hatalara neden olabilir.

Aşağıdaki kodu örnek olarak alın.

#include <stdio.h>

int main() {
    int i, j;
    i = 20;
    j = 30;

    printf("(1) i: %d, j: %d\n", i, j);

    {
        int i;
        i = 88;
        j = 99;
        printf("(2) i: %d, j: %d\n", i, j);
    }

    printf("(3) i: %d, j: %d\n", i, j);

    return 0;
}

Gördüğünüz gibi, iki kez i ilan ettim. Daha kesin olmak gerekirse, ikisi de i olan iki değişken ilan ettim. Bunun bir hataya yol açabileceğini düşünebilirsiniz, ancak değildir, çünkü iki i değişkeni farklı kapsamlardadır. Bu fonksiyonun çıktısına baktığınızda bunu daha net görebilirsiniz.

(1) i: 20, j: 30
(2) i: 88, j: 99
(3) i: 20, j: 99

İlk önce, sırasıyla 20 ve 30'u i ve j atarız. Öyleyse, küme parantezlerinin içine, 88 ve 99 atarız. Öyleyse, neden j değerini koruyor ama i tekrar 20'ye dönüyor? İki farklı i değişkeni nedeniyle.

Kıvrımlı küme parantezleri arasında, 20 değerine sahip i değişkeni gizlenir ve erişilemez, ancak yeni j ilan etmediğimiz için, dış kapsamdan j özelliğini kullanıyoruz. İçteki küme parantezlerini bıraktığımızda, 88 değerini tutan i ortadan kalkar ve yine 20 değeri olan i'a erişiriz.

Bazen bu davranış iyi bir şeydir, başka zamanlar, belki de değildir, ancak açık bir şekilde C'nin bu özelliğini ayırt etmeden kullanırsanız, kodunuzu gerçekten kafa karıştırıcı ve anlaşılması zor hale getirebileceğiniz açıktır.

3
haydenmuhl

Derleyiciniz izin veriyorsa, istediğiniz yerde bildirmek için para cezası. Aslında, bir işlevi yerine kullanmak yerine değişkeni tanımladığınızda kod daha okunaklıdır (IMHO); değişkeni başlatmayı veya değişkeni kazayla gizlemeyi unutmak.

1
Anders

Bir yayın aşağıdaki kodu gösterir:

//C99
printf("%d", 17);
int z=42;
printf("%d", z);

//ANSI C
printf("%d", 17);
{
    int z=42;
    printf("%d", z);
}

ve bence bunun anlamı, bunların eşdeğer olmasıdır. Onlar değil. İnt z bu kod snippet'inin altına yerleştirilirse, birinci z tanımına göre yeniden tanımlanma hatasına neden olur, ikinciye karşı değil.

Ancak, birden çok satır:

//C99
for(int i=0; i<10; i++){}

çalışır. Bu C99 kuralının inceliklerini gösteriliyor.

Şahsen, bu C99 özelliğini tutkuyla kapattım.

Bir değişkenin kapsamını daralttığı argümanı, bu örneklerde gösterildiği gibi yanlıştır. Yeni kural uyarınca, tüm bloğu tarayana kadar bir değişkeni güvenle bildiremezsiniz, oysa önceden yalnızca her bloğun başında neler olduğunu anlamanız gerekiyordu.

1
user2073625

K & R'nin C Programlama Diline Göre - 

C de, tüm değişkenler kullanılmadan önce, genellikle çalıştırılabilir ifadelerden önce fonksiyonun

Burada Word'ü genellikle görmeniz gerekmiyor ..

0
Gagandeep kaur

Dahili olarak bir fonksiyona lokal olan tüm değişkenler bir yığında veya CPU kayıtlarının içinde tahsis edilir ve daha sonra üretilen makine kodu, derleyici kötü ise veya CPU için yeterli kayıt yoksa, kayıtlar ve yığın (kayıt dökülme adı verilir) arasında geçiş yapar. tüm topları havada sallar.

Yığın üzerine malzeme tahsis etmek için CPU, biri Stack Pointer (SP) ve diğeri - Base Pointer (BP) veya kare işaretçisi (geçerli işlev kapsamına yerel yığın çerçevesi anlamına gelen) olarak adlandırılan iki özel kayıt defterine sahiptir. SP bir yığındaki geçerli konumu işaret ederken, BP çalışan veri kümesine (üstte) ve işlev argümanlarına (altta) işaret eder. İşlev çağrıldığında, arayan/ebeveyn işlevinin BP'sini yığının üzerine (SP ile işaretlenir) iter ve mevcut SP değerini yeni BP olarak ayarlar, ardından SP yazmaçlardan yığına dökülen bayt sayısı, hesaplama yapar ve geri döndüğünde, yığından çıkartarak ebeveyninin BP'sini geri yükler.

Genelde, değişkenlerinizi kendi {} - kapsamı içinde tutmak, derleyiciyi hızlandırabilir ve derleyicinin hangi değişkenlerin nerede ve nasıl kullanıldığını belirlemek için yürümesi gereken grafiğin boyutunu küçülterek oluşturulan kodu iyileştirebilir. Bazı durumlarda (özellikle goto işin içine girdiğinde) derleyici, derleyiciye kullanım kapsamını açıkça belirtmediğiniz sürece, değişkenin artık kullanılmayacağı gerçeğini kaçırabilir. Derleyicilerin program grafiğini aramak için zaman/derinlik sınırı olabilir.

Derleyici yan yana bildirilen değişkenleri aynı yığın alanına yerleştirebilir, yani bir tanesi yüklendiğinde diğerini ön belleğe alacaktır. Aynı şekilde, register değişkenini bildirmek, derleyiciye, söz konusu değişkenin her ne pahasına olursa olsun yığın üzerine dökülmesini önlemek istediğiniz bir ipucu verebilir.

Sıkı C99 standardı, bildirimlerden önce açıkça { gerektirir, oysa C++ ve GCC tarafından eklenen uzantılar, goto ve case ifadelerini karmaşıklaştıran, vücutta daha fazla değişiklik yapılmasına izin verir. C++ ayrıca, döngü kapsamı ile sınırlı olan, döngü başlatma için içeriğin bildirilmesine izin verir.

Son fakat en az değil, başka bir insan kodunuzu okuduğu için, kullanım yerlerinde lokalize edilmek yerine yarım yüz değişken bildirimi ile doldurulmuş bir işlevin tepesini gördüğünde çok zor olurdu. Ayrıca kullanımlarını yorumlamayı da kolaylaştırır.

TLDR: Değişkenlerin kapsamını açıkça belirtmek için {} kullanılması hem derleyiciye hem de insan okuyucusuna yardımcı olabilir.

0
SmugLispWeenie

Clang ve gcc ile, aşağıdakilerle ilgili büyük sorunlarla karşılaştım: .... 

  {
    char f1[]="This_is_part1 This_is_part2";
    char f2[64]; char f3[64];
    sscanf(f1,"%s %s",f2,f3);      //split part1 to f2, part2 to f3 
  }

ne derleyici, f1, f2 veya f3'ü bloğun içinde sevmedi. F1, f2, f3'ün fonksiyon tanım alanına taşınması gerekiyordu. derleyici blok ile bir tamsayı tanımına aldırmadı.

0