Değişken başlatma üzerine atlamak kötü biçimlendirilmiş mi yoksa tanımlanmamış davranışa neden oluyor mu?


17

Bu kodu düşünün:

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

GCC ve Clang bunu reddeder , çünkü bar:değişken başlatmayı atlar. MSVC (kullanılmasının haricinde hiç şikayet etmiyor xsonra bar:nedenleri bir uyarı).

Şununla benzer bir şey yapabiliriz switch:

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

Şimdi her üç derleyici de hata yayar .

Bu parçacıklar kötü biçimlendirilmiş mi? Yoksa UB'ye mi neden oluyorlar?

Her ikisinin de kötü biçimlenmiş olduğunu düşünürdüm, ama standardın vahiy kısımlarını bulamıyorum. [stmt.goto] bu konuda hiçbir şey söylemez ve [stmt.select] de söylemez .


1
xAtlamadan sonra kullanırsanız sorun daha önemsiz olurdu .
Jarod42

1
standart değil, ama burada bununla ilgili bazı bilgiler bulabilirsiniz: en.cppreference.com/w/cpp/language/goto özellikle: "Kontrolün transferi herhangi bir otomatik değişkenin kapsamına girerse (örneğin, bir bildirim üzerinde ileri atlayarak) ifadesi), program kötü biçimlendirilmiş (derlenemez), ... "
idclev 463035818

/permissive-Bayrağı MSVC'ye ekleyin, bu da şikayet edecektir. Bu bayrak olmadan MSVC'nin davranışının iyi tanımlanıp tanımlanmadığını bilmiyorum (varsayalım, aksi halde neden buna izin vereceklerdi?).
Ceviz

@walnut "aksi halde neden izin verdiler" Muhtemelen geriye dönük uyumluluk için veya standardı fazla önemsememeleri nedeniyle. Tüm büyük derleyiciler varsayılan ayarlar altındaki standarda uymaz.
HolyBlackCat

Yanıtlar:


20

Başlatma işlemi boş olmadığında kötü şekillenir.

[Stmt.dcl]

3 Bir bloğa transfer etmek mümkündür, ancak başlatmalarla bildirimleri atlayacak şekilde değil (koşullar ve init deyimleri dahil). Otomatik depolama süresine sahip bir değişkenin kapsam dışında olmadığı bir noktadan, değişkenin başlangıç ​​durumuna getirilmediği sürece ([basic.life]) kapsamın içinde olduğu bir noktaya atlayan program. Böyle bir durumda, boşaltma ile değişkenler, açıklama sırasına göre oluşturulur.

Başlatıcı, başlatmayı boş bırakır. Aksine, bu

void foo()
{
    goto bar;
    int x; // no initializer
    bar: ;
}

iyi biçimlendirilmiş olur. Gerçi xbelirsiz bir değerle kullanımla ilgili olağan uyarılar geçerli olacaktır.


Değişken bildirimlerin zaten bir kapsamdaki ilk şey olması gerekmez mi?
Cruncher

4
@Cruncher - C89 gerektiriyordu. C ++ hiçbir zaman yapmadı ve modern C de artık yapmadı.
StoryTeller - Unlander Monica

3

Gönderen git açıklamada :

Eğer kontrolün transferi herhangi bir otomatik değişkenin kapsamına girerse (örn. Bir beyan ifadesi üzerinde ileri atlayarak), kapsamı girilen tüm değişkenler

  1. başlatıcılar olmadan bildirilen skaler tipler
  2. önemsiz varsayılan kurucuları ve başlatıcılar olmadan bildirilen önemsiz yıkıcıları olan sınıf türleri
  3. Yukarıdakilerden birinin cv nitelikli sürümleri
  4. yukarıdakilerden birinin dizileri
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.