Kullanılmayan dönüş değerleri neden boşa dönüştürülür?


112
int fn();

void whatever()
{
    (void) fn();
}

Kullanılmayan bir dönüş değerini geçersiz hale getirmek için herhangi bir neden var mı, yoksa bunun tam bir zaman kaybı olduğunu düşünmekte haklı mıyım?

Takip et:

Bu oldukça kapsamlı görünüyor. Kendi kendini belgeleyen kod yorumlardan daha iyi olduğundan, kullanılmayan bir dönüş değerini yorumlamaktan daha iyi olduğunu düşünüyorum. Kişisel olarak, gereksiz gürültü olduğu için bu uyarıları kapatacağım.

Bu yüzden bir böcek kaçarsa sözlerimi yerim ...

Yanıtlar:


79

David'in cevabı , diğer "geliştiricilere" bu işlevin geri döndüğünü bildiğinizi ancak açıkça görmezden geldiğinizi açıkça göstermek için bunun motivasyonunu fazlasıyla kapsıyor.

Bu, gerekli hata kodlarının her zaman ele alınmasını sağlamanın bir yoludur.

Bence C ++ için burası muhtemelen C tarzı dökümleri de kullanmayı tercih ettiğim tek yer, çünkü tam statik döküm gösterimini kullanmak burada aşırı derecede abartılı gibi geliyor. Son olarak, bir kodlama standardını gözden geçiriyorsanız veya bir tane yazıyorsanız, aşırı yüklenmiş operatörlere yapılan çağrıların (işlev çağrısı gösterimi kullanmadan) da bundan muaf tutulması gerektiğini açıkça belirtmek iyi bir fikirdir:

class A {};
A operator+(A const &, A const &);

int main () {
  A a;
  a + a;                 // Not a problem
  (void)operator+(a,a);  // Using function call notation - so add the cast.

C tarzı oyuncuları da tercih ettiğim tek yer burası. kodlama standardımda, "a + a" 'ya (void) ekleyeceğim; çok (tabii ki doğru şekilde parlatılmış: p)
Johannes Schaub - litb

8
Biraz konu dışı, ama neden "a + a" yapasınız? dönüş değerini kullanmadan böyle mi? Bu bana gerçekten yan etkilerin kötüye kullanılması gibi görünüyor ve kodun amacını belirsizleştiriyor.
Rob K

5
Her gün kullanacağınız "a = a" olacaktır. Bu, nesneye atanmış olanı döndürür (iyi davranan tüm sınıflar için! :)). Başka bir örnek: os << "Merhaba Dünya" << std :: endl. Her biri "os" nesnesini döndürür.
Richard Corden

46

İşte bunu, işlevin bir dönüş değeri olduğunu kabul etmek için kullanıyoruz, ancak geliştirici bunu göz ardı etmenin güvenli olduğunu iddia etti. Soruyu C ++ olarak etiketlediğiniz için static_cast kullanıyor olmalısınız :

static_cast<void>(fn());

Derleyici, dönüş değerinin void'e dönüştüğü sürece çok az anlam ifade eder.


Kullanılmayan dönüş değerleri ile ilgili uyarıyı bastırır mı?
Paul Tomblin

Hayır değil. @Mykola: GCC4 ile, dönüş değerinin göz ardı edilmemesi gerektiğini söyleyen ve bir uyarıyı tetikleyecek bir özellik ekleyebilirsiniz.
David Holm

2
Ben g ++ kullanıyorum ve bu tür bir cast ile bile uyarı veriyor.
klew

2
hangi uyarı seçeneğini kullanıyorsunuz? -Wunused-değeri çevremdeki uyarıyı tetiklemiyor
Mykola Golubyev

VC ++ 'da uyarıyı bastırır
jalf

39

Bunu yapmanın gerçek nedeni, C kodunda kullanılan lint adı verilen bir araca dayanıyor .

Olası sorunları arayan kodu analiz eder ve uyarılar ve öneriler verir. Bir işlev, daha sonra kontrol edilmeyen bir değer döndürürse, lintbunun yanlışlıkla olması durumunda uyarırdı. lintBu uyarıyı susturmak için aramayı adresine yönlendirirsiniz (void).


2
Bu şekilde başlamış olabilir, ancak çoğu aracın artık bunun gibi uyarıları bastırmak için başka mekanizmaları var. Ayrıca - bunun neden başladığına bakılmaksızın, özellikle güvenlik açısından kritik kod alanında bu, geliştiricinin niyetlerini "belgelemenin" olağan yolu haline geldi.
Richard Corden

5
GCC bunun için -Wall ile uyarı verir.
greyfade

23

Şuraya voidçevrim, kullanılmayan değişkenler ve kaydedilmemiş dönüş değerleri veya ifadeler için derleyici uyarılarını bastırmak için kullanılır.

Standart (2003) §5.2.9 / 4'te diyor ki,

Herhangi bir ifade açıkça "cv void" türüne dönüştürülebilir. İfade değeri atılır .

Böylece yazabilirsiniz:

//suppressing unused variable warnings
static_cast<void>(unusedVar);
static_cast<const void>(unusedVar);
static_cast<volatile void>(unusedVar);

//suppressing return value warnings
static_cast<void>(fn());
static_cast<const void>(fn());
static_cast<volatile void>(fn());

//suppressing unsaved expressions
static_cast<void>(a + b * 10);
static_cast<const void>( x &&y || z);
static_cast<volatile void>( m | n + fn());

Tüm formlar geçerlidir. Genelde şu şekilde kısaltırım:

//suppressing  expressions
(void)(unusedVar);
(void)(fn());
(void)(x &&y || z);

Ayrıca sorun değil.


1
Derleyici uyarılarını her zaman kapatmaması dışında. gcc, void'e geçişe yanıt vermiyor gibi görünüyor
Matt

@Matt: GCC'nin hangi sürümünü kullanıyorsunuz? Kodunuzu ideone.com veya stacked-crooked.com adreslerine gönderebilir misiniz (ikincisi daha iyidir).
Nawaz

1
Standart "atıldı" ifadesi, uyarının linterler tarafından gündeme getirilmemesi gerektiği anlamına mı geliyor?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
@CiroSantilli 巴拿馬 文件 六四 事件 法轮功: .... bu ilginç bir soru. Şu anda bunun cevabını bilmiyorum. Bir şekilde tanıyorsanız lütfen benimle paylaşın.
Nawaz


4

Boşluğa atmak maliyetsizdir. Yalnızca derleyiciye nasıl davranılacağı bilgisidir.


1
Yazma zamanı ve sonraki sefer kodu okuma, anlama (ve sonra görmezden gelme) ücretsiz ise "maliyetsizdir". IMO, yazmak (void)bana zaman ve enerji harcıyor ve yazarın ifadelerin nasıl çalıştığını bilip bilmediğini merak etmeme neden oluyor.
wallyk

4

Programınızın işlevini geçersiz kılmak anlamsızdır. David'in yanıtında önerildiği gibi, kodu okuyan kişiye bir sinyal vermek için kullanmamanız gerektiğini de iddia ediyorum. Niyetleriniz hakkında bir şeyler iletmek istiyorsanız, bir yorum kullanmak daha iyidir. Böyle bir oyuncu kadrosu eklemek sadece garip görünecek ve olası neden hakkında sorular ortaya çıkaracaktır. Sadece benim fikrim...


2
Bu, başkalarına geri dönüş değerini umursamadığınızı, sadece onu halletmeyi unutmadığınızı açıkça söylemek için bilinen bir kalıptır.
Spidey

For the functionality of you program casting to void is meaninglessKendini belgelendirme ve derleme sırasındaki uyarıların sayısı için gerçekten değil. Kod kendini açıkladığında you should not use it to signal something to the person that is reading the code [...] it is better to use a comment.en iyi yorum yorum olmamasıdır . Ve yine, geçerli bir uyarı derleyicisini bu süreçte mutlu tutar.
underscore_d

'Böyle bir oyuncu kadrosu eklemek sadece tuhaf görünecek ve olası neden hakkında sorular doğuracaktır'. Bunlardan birini keşfettim ve bu yüzden bunu okuyorum. Eğitimsiz beynime gizemli istismar gibi göründü.
mynameisnafe

1

Ayrıca, kodunuzun MISTA (veya diğer) standartlarına uygun olduğunu doğrularken, LDRA gibi otomatik araçlar, döndürülen değeri açıkça (void) olarak değiştirmediğiniz sürece, bir değer döndürmeden dönüş türüne sahip bir işlevi çağırmanıza izin vermez.


0

C ++ 17 [[nodiscard]]

C ++ 17, bir öznitelikle "geri dönüş değeri göz ardı edilen işi" standardize etti.

Bu nedenle, uyumlu uygulamaların her zaman yalnızca nodiscard verildiğinde uyaracağını, aksi takdirde asla uyarmayacağını .

Misal:

main.cpp

[[nodiscard]] int f() {
    return 1;
}

int main() {
    f();
}

derlemek:

g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -o main.out main.cpp

sonuç:

main.cpp: In function int main()’:
main.cpp:6:6: warning: ignoring return value of int f()’, declared with attribute nodiscard [-Wunused-result]
    6 |     f();
      |     ~^~
main.cpp:1:19: note: declared here
    1 | [[nodiscard]] int f() {
      | 

Aşağıdakilerin tümü uyarıdan kaçınır:

(void)f();
[[maybe_unused]] int i = f();

Kullanamadım maybe_unusedDoğrudan f()görüşmede :

[[maybe_unused]] f();

verir:

main.cpp: In function int main()’:
main.cpp:6:5: warning: attributes at the beginning of statement are ignored [-Wattributes]
    6 |     [[maybe_unused]] f();
      |     ^~~~~~~~~~~~~~~~

(void)Dökme çalışma standart zorunlu olduğu görünmüyor ama "teşvik" olduğunu: Ben kasıtlı bir [[nodiscard]] dönüş değeri göz ardı nasıl?

Ayrıca uyarı mesajından da görüldüğü gibi, uyarıya bir "çözüm" eklemektir -Wno-unused-result :

g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -Wno-unused-result -o main.out main.cpp

elbette bunun gibi küresel çapta uyarıları görmezden gelmenizi tavsiye etmem.

C ++ 20 ayrıca aşağıdaki adreste belirtildiği nodiscardgibi bir neden eklemenizi sağlar [[nodiscard("reason")]]: https://en.cppreference.com/w/cpp/language/attributes/nodiscard

GCC warn_unused_result özelliği

Standartlaştırılmadan önce [[nodiscard]]ve C için nitelikleri standartlaştırmaya karar vermeden önce, GCC aşağıdakilerle tam olarak aynı işlevselliği uyguladı warn_unused_result:

int f() __attribute__ ((warn_unused_result));

int f() {
    return 1;
}

int main() {
    f();
}

hangi verir:

main.cpp: In function int main()’:
main.cpp:8:6: warning: ignoring return value of int f()’, declared with attribute warn_unused_result [-Wunused-result]
    8 |     f();
      |     ~^~

ANSI C Bunun için bir standart olmadığı için, ANSI C C standart kütüphanesi fonksiyonları özniteliği ya da değil ve bu nedenle tüm uygulamaları veya işaretlenmiş edilmemelidir ne kendi kararlarını yapmış hangi belirtmez o zaman unutulmamalıdır warn_unuesd_result, hangi bu nedenle genel olarak(void) , herhangi bir uygulamada uyarılardan tamamen kaçınmak için standart kütüphane işlevlerine yapılan herhangi bir çağrının geri dönüşünü yok saymak için çevirmeyi .

GCC 9.2.1, Ubuntu 19.10'da test edilmiştir.

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.