Kullanılmayan değişkenlerle ilgili bir uyarıyı en iyi nasıl sustururum?


237

Bir çapraz platform uygulamam var ve bazı işlevlerimde işlevlere iletilen tüm değerler kullanılmıyor. Bu nedenle GCC'den kullanılmayan değişkenler olduğunu belirten bir uyarı alıyorum.

Uyarı etrafında kodlamanın en iyi yolu ne olurdu?

#İfdef fonksiyonun etrafında mı?

#ifdef _MSC_VER
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal qrLeft, qreal qrTop, qreal qrWidth, qreal qrHeight)
#else
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal /*qrLeft*/, qreal /*qrTop*/, qreal /*qrWidth*/, qreal /*qrHeight*/)
#endif
{

Bu çok çirkin ama derleyicinin tercih ettiği gibi görünüyor.

Yoksa işlevin sonunda değişkene sıfır atayabilir miyim? (ki bu bir nefret ediyorum çünkü bir derleyici uyarısını susturmak için program akışındaki bir şeyi değiştiriyor).

Doğru bir yol var mı?


7
Geçen Kasım ayında benzer bir soru sorduğunuzu fark ettim. Bu yüzden tanıdık geliyor! ;) stackoverflow.com/questions/308277/…
Alex B

9
Neden sadece her iki derleyici için yorum yapmıyorsunuz? Eğer argüman birinde kullanılmazsa, muhtemelen diğerinde kullanılmayacaktır ...
Roger Lipscombe

12
Qt'nin bunun için bir Q_UNUSEDmakrosu olduğunu bilmelisiniz . Belgelere bakın.
Evan Teran

1
C çözümü C ++ 'da da iyi çalışıyor: stackoverflow.com/a/3599170/1904815
JonnyJD

Eğer derleyici özgü yapı bayraklarını olabilir eğer -Wno-kullanılmayan parametreli da bir seçenek olabilir
Kod Abominator

Yanıtlar:


327

Şunları yapabilirsiniz "koymak (void)var;ifadesi" (hiçbir şey yapmaz) bir derleyici kullanıldığı görür böylece. Bu derleyiciler arasında taşınabilir.

Örneğin

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

Veya,

#define UNUSED(expr) do { (void)(expr); } while (0)
...

void foo(int param1, int param2)
{
    UNUSED(param2);
    bar(param1);
}

22
+1 - yine de değişkeni orada olmasa bile neden kullanmadığınızı belgeleyeceğim.
Tobias Langner

18
Bu nasıl Q_UNUSEDprensipte uygulanmaktadır.
Dmitry Volosnykh

11
@Cameron sadece C ++ 'da parametre adını atlayabilirsiniz. Eğer şablon ayarlanmışsa, C dilinde kullanılmayacaktır, bu nedenle dökümden hile numarasına ihtiyacınız yoktur.
Alex B

13
Sadece de #define UNUSED(expr) (void)(expr)yapmalısınız (do-while olmadan).
JonnyJD

7
Bunu değişken bir şablon için nasıl yapacağımı merak ediyorum. In template<typename... Args> void f(const Args&... args)ben yazamam (void)args;ya (void)args...;çünkü her ikisi sözdizimi hatalardır.
panzi

101

GCC ve Clang'da __attribute__((unused))hedefinize ulaşmak için önişlemci direktifini kullanabilirsiniz.
Örneğin:

int foo (__attribute__((unused)) int bar) {
   return 0;
}

1
Bu, geri arama işlevleri için en iyi çözümdür.
Sonic Atom

1
Ayrıca clang tarafından da desteklenmektedir: clang.llvm.org/docs/…
Alexander


39

Mevcut çözümünüz en iyisidir - kullanmıyorsanız parametre adını yorumlayın. Bu tüm derleyiciler için geçerlidir, bu yüzden ön işlemciyi GCC için özel olarak yapmak zorunda değilsiniz.


7
Sadece bu cevabı güçlendirmek için #ifdef'e ihtiyacınız yok, sadece kullanılmayan parametre adlarını yorumlayın.
quamrana

4
Parametre geri arama bir parçası olduğu ve bunu derleme tatili (bu yüzden neden g++bu konuda uyarı olduğundan emin değilim ) bir durumda var. Böyle bir durumda, ne tavsiye ederim?
Drew Noakes

1
Kullanılmayan parametreler / * yorumlandı * / ile satır içi sanal bir yöntem düşünün, arabirimin istemcisi çoğu IDE'de otomatik tamamlama sırasında parametre adını görmez. Bu durumda UNUSED () çözümü daha az temiz olmasına rağmen daha uygundur.
cbuchart

Bence daha basit daha iyi, yorum yapmak çok açık
fievel

26

C ++ 17 Güncellemesi

C ++ 17'de, [dcl.attr.unused] ile kapsanan [[belki_unused]] özelliğini kazanırız

Özellik belirteci maybe_unused, bir adın veya varlığın muhtemelen kasıtlı olarak kullanılmadığını gösterir. Her nitelik listesinde en fazla bir kez görünecek ve hiçbir nitelik-argüman-maddesi bulunmayacaktır. ...

Misal:

 [[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
    assert(b);
 }

Uygulamalar, NDEBUG tanımlı olsun veya olmasın, b'nin kullanılmadığı konusunda uyarmamalıdır. —End örneği]

Aşağıdaki örnek için:

int foo ( int bar) {
    bool unused_bool ;
    return 0;
}

Hem clang hem de gcc, bar ve unused_bool için -Wall -Wextra kullanarak bir tanı oluşturur ( Canlı olarak görün ).

[[Maybe_unused]] eklenirken tanılama susturulur :

int foo ([[maybe_unused]] int bar) {
    [[maybe_unused]] bool unused_bool ;
    return 0;
}

canlı görün .

C ++ 17'den önce

C ++ 11'de , kullanılmayan değişkenin yakalanmasıyla UNUSEDbir lambda ifadesi ( Ben Deane aracılığıyla ) kullanılarak makronun alternatif bir formu oluşturulabilir :

#define UNUSED(x) [&x]{}()

Aşağıdaki örnek göz önüne alındığında lambda ifadesinin derhal çağrılması optimize edilmelidir:

int foo (int bar) {
    UNUSED(bar) ;
    return 0;
}

Godbolt'ta aramanın optimize edildiğini görebiliriz :

foo(int):
xorl    %eax, %eax
ret

5
Yani C ++ 11'den söz edip bir makro sunmayı başarabiliyor musunuz? Ah! Belki bir fonksiyon kullanmak daha temiz olurdu? template <class T> inline void NOTUSED( T const & result ) { static_cast<void>(result); }Sanırım, fonksiyonda bir lambda da kullanabilirsiniz.
Alexis Wilke

godbolt harika bir kaynaktır
yano

5
[&x]{}()uyarıyı gerçekten susturmaz, ancak uyarıyı arayan işlevinden lambda'ya iletir. Derleyicilerin bunu bir uyarı olarak tanımlaması zaman alacaktır, ancak clang-tidy zaten yakalama listesinde kullanılmayan bir değişken hakkında şikayet ediyor.
nVxx

25

Daha da temiz bir yol, değişken adlarını yorumlamaktır:

int main(int /* argc */, char const** /* argv */) {
  return 0;
}

8
Doxygen'iniz varsa ve parametreleri belgelemek istiyorsanız bu iyi değildir.
Alexis Wilke

18
@AlexisWilke: Bu, oksijende bir böcek olarak nitelendirilir, IMO
6502

3
#İfdef DOXYGEN üzerinden # if YOUR_PROJECT_UNUSED (argname) koşulunu koşullu olarak tanımlayabilirsiniz; böylece doxygen, int main aracılığıyla (int YOUR_PROJECT_UNUSED (argc), ...) göremez. Muhteşem değil, ama işe yarıyor.
mabraham

Bu tür birçok iç içe yorum ile bir kod bloğunu yorumlamak çok acı verici buluyorum. (derleyici her biri hakkında şikayetçi).
Jeff McClintock

@JeffMcClintock sadece tek satırlık yorumlar kullanır. Çoğu iyi editör dikey blok düzenlemeyi destekler (örneğin Vim'de [Ctrl] + [V]). Aksi takdirde, #if 0 / #endifblok yorumları kullanın .
Ruslan

24

Bir iş arkadaşım beni buradaki bu güzel makroya işaret etti

Kolaylık için aşağıdaki makroyu ekleyeceğim.

#ifdef UNUSED
#elif defined(__GNUC__) 
# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 
#elif defined(__LCLINT__) 
# define UNUSED(x) /*@unused@*/ x 
#else 
# define UNUSED(x) x 
#endif

void dcc_mon_siginfo_handler(int UNUSED(whatsig))

12
"güzel" "makro" "c ++" - 2. seçin
Jeff McClintock

23

varsayılan olarak bu uyarıları işaretlemez. Bu uyarının -Wunused-parameterderleyiciye geçirilerek veya dolaylı olarak iletilerek -Wall -Wextra(veya muhtemelen başka bir bayrak birleşimi yoluyla) açılmış olması gerekir .

Kullanılmayan parametre uyarıları -Wno-unused-parameterderleyiciye iletilerek kolayca bastırılabilir , ancak bu devre dışı bırakma bayrağının derleyici komut satırında bu uyarı için olası etkinleştirme işaretlerinden sonra gelmesi gerektiğini unutmayın, böylece etkili olabilir.


2
Her ne kadar bu soruya en iyi cevap olmayabilir (çünkü soru uyarıdan nasıl kaçınacağımız, nasıl devre dışı bırakılacağı değil), bu cevap google'dan (benim gibi) gelen insanlar ("nasıl bu uyarıyı devre dışı bırakmak için "). Bu yüzden +1 veriyorum, cevabınız için teşekkürler!
mozzbozz

13

bir veya daha fazla parametreyi kullanılmayan olarak bildirmek için makro içermeyen ve taşınabilir bir yol :

template <typename... Args> inline void unused(Args&&...) {}

int main(int argc, char* argv[])
{
    unused(argc, argv);
    return 0;
}

Çok iyi, ancak bunun C ++ 11 (veya daha yenisi) gerektirdiğini unutmayın.
Paul R

Bu cevaba oy verdim çünkü sadece uyarıdan kurtulmak için derleme zamanını (şablonlar kullanarak) feda etmek istemem.
Konrad Kleine

@KonradKleine: Bu muhtemelen ne kadar derleme zamanı tüketebilir? Bilgisayarımda test ederek, bu kullanılmayan () çağrılardan binini saniyenin onda birinde gerçekleştirebilirim.
Daniel McLaury

@DanielMcLaury bu sadece benim tahminimdi ve hiç deney yapmadım.
Konrad Kleine

8

Önişlemci direktiflerinin kullanılması çoğu zaman kötü olarak kabul edilir. İdeal olarak zararlılardan kaçınmak istersiniz. Derleyicinin kodunuzu anlamasını sağlamanın, diğer programcıların kodunuzu anlamasını sağlamanın çok daha zor olduğunu unutmayın. Burada bunun gibi birkaç düzine vaka, kendiniz için daha sonra veya şu anda başkaları için okumayı çok zorlaştırıyor.

Bunun bir yolu parametrelerinizi bir çeşit argüman sınıfına koymak olabilir. Daha sonra, değişkenlerin yalnızca bir alt kümesini (gerçekten 0 atamanıza eşdeğer) veya her bir platform için bu bağımsız değişken sınıfının farklı uzmanlıklarına sahip olabilirsiniz. Ancak buna değmeyebilir, uygun olup olmadığını analiz etmeniz gerekir.

İmkansız şablonları okuyabiliyorsanız, "Olağanüstü C ++" kitabında gelişmiş ipuçları bulabilirsiniz. Kodunuzu okuyan insanlar, bu kitapta öğretilen çılgın şeyleri kapsayacak şekilde becerilerini alabilirlerse, kolayca okunabilen güzel bir kodunuz olurdu. Derleyici aynı zamanda ne yaptığınızın da farkında olacaktır (önişleme yaparak her şeyi gizlemek yerine)


5
"Önişlemci direktiflerini kullanmak çoğu zaman kötü olarak kabul edilir." Gerçekten mi? Kim tarafından?
Graeme Perrow

12
Kapsamı önemseyen, düzgün hata ayıklayabilen veya akıl sağlığına önem veren herkes tarafından.
Bill

2
@Graeme, sadece 4 çizgisini gördüğümüzde masum görünüyor, ancak etrafına yaymak baş ağrısına neden oluyor. #ifdef temel olarak, derleyicinin yalnızca birini göreceği bir kaynak kodunun birden çok sürümünü koymanıza izin verir. Bill'in belirttiği gibi, hata ayıklamayı da zorlaştırır. Çeşitli kitap ve bloglardaki önişlemci direktiflerinin kötülüklerini okudum ve kendim de deneyimledim. Tabii ki, her şey görecelidir. Bazen önişlemci direktifleri mantıklıdır çünkü başka her şeyin daha kötü sonuçları olur ve benim düşüncem burada mümkün olduğunca kaçınılması gerektiğidir.
Ben Dadsetan

1
Aşırı kullanım kötü, ama #define UNUSED(expr) (void)(expr)uygun diyebilirim .
JonnyJD

7

İlk olarak uyarı, başlık dosyasında değil kaynak dosyada değişken tanımıyla oluşturulur. API belgelerini oluşturmak için doxygen gibi bir şey kullanıyor olabileceğinizden, başlık bozulmamış kalabilir ve olmalıdır.

Kaynak dosyalarda tamamen farklı bir uygulamanız olduğunu varsayacağım. Bu durumlarda, rahatsız edici parametreyi yorumlayabilir veya yalnızca parametreyi yazabilirsiniz.

Misal:

func(int a, int b)
{
    b;
    foo(a);
}

Bu şifreli görünebilir, bu yüzden UNUSED gibi bir makro tanımladı. MFC'nin yaptığı gibi:

#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif

Bunun gibi hala hata ayıklama yapılarında uyarı görüyorsunuz, yardımcı olabilir.


4

Parametre adlarını her zaman yorumlamak güvenli değil mi? Eğer değilse, böyle bir şey yapabilirsiniz

#ifdef _MSC_VER
# define P_(n) n
#else
# define P_(n)
#endif

void ProcessOps::sendToExternalApp(
    QString sAppName, QString sImagePath,
    qreal P_(qrLeft), qreal P_(qrTop), qreal P_(qrWidth), qreal P_(qrHeight))

Bu var biraz daha az çirkin.


4
Param adının C ++ 'da (C' de) zorunlu olmaması, uyarıyı önlemenin standart ve kolay bir yolunu vermektir.
AProgrammer

1
@hacker, öyle olduğunu söylememiştim. Özellikle ortak alt küme olduğunu düşündüğünüz bölgelerde olduklarında C ve C ++ arasındaki farkları gösterme eğilimindeyim ... Karışık bir kod tabanı üzerinde çalıştığım için sadece bir alışkanlık.
AProgrammer

4

(void)param2Uyarıyı susturmanın yolu yerine bunu gördüm :

void foo(int param1, int param2)
{
    std::ignore = param2;
    bar(param1);
}

Bunun C ++ 11'e eklendiği anlaşılıyor


Bir şey yapıyor gibi görünüyor, derledikten sonra göz ardı edilmiyor.
GyuHyeon Choi

3

Bir UNREFERENCED_PARAMETER(p)işe yarayabilir. Windows sistemleri için WinNT.h'de tanımlandığını ve gcc için de kolayca tanımlanabileceğini biliyorum (eğer zaten yoksa).

UNREFERENCED PARAMETER(p) olarak tanımlanır

#define UNREFERENCED_PARAMETER(P)          (P)

WinNT.h.


2

Derleyicinin bayrağını, örneğin GCC bayrağını kullanın: -Wno-unused-variable


1

__unusedDerleyiciye değişkenin kullanılamayabileceğini söylemek için kullanabilirsiniz .

- (void)myMethod:(__unused NSObject *)theObject    
{
    // there will be no warning about `theObject`, because you wrote `__unused`

    __unused int theInt = 0;
    // there will be no warning, but you are still able to use `theInt` in the future
}

2
Hangi derleyici? Çünkü __unusedstandart C ++ ve daha da önemlisi, ne de ne gönderdi ... Bu Objective-C. Bu nedenle, bu cevap yalnızca belirli derleyiciler için yararlıdır ve kodu taşınabilir değildir ve gerçekte geçerli değildir, çünkü kullanıcı kodu, __uygulama için ayrılan tanımlayıcıları kullanmaya yönelik değildir.
underscore_d

1

C ++ 11, kullandığım çözüm bu:

template<typename... Ts> inline void Unreferenced(Ts&&...) {}

int Foo(int bar) 
{
    Unreferenced(bar);
    return 0;
}

int Foo2(int bar1, int bar2) 
{
    Unreferenced(bar1, bar2);
    return 0;
}

Taşınabilir (en azından modern msvc, clang ve gcc'de) olduğu ve optimizasyonlar etkinleştirildiğinde fazladan kod üretmediği doğrulandı. Optimizasyon olmadan, ekstra işlev çağrısı gerçekleştirilir ve parametrelere referanslar yığına kopyalanır, ancak hiçbir makro yoktur.

Ek kod bir sorunsa, bu bildirimi kullanabilirsiniz:

(decltype(Unreferenced(bar1, bar2)))0;

ancak bu noktada bir makro daha iyi okunabilirlik sağlar:

#define UNREFERENCED(...) { (decltype(Unreferenced(__VA_ARGS__)))0; }

1

Bu iyi çalışıyor ama C ++ 11 gerektirir

template <typename ...Args>
void unused(Args&& ...args)
{
  (void)(sizeof...(args));
}

1
Peki ya C ++ 14 gerektirir ve C ++ 11'de çalışmaz? Hiçbir şey göremiyorum. Ayrıca, ALLCAPSmakrolar dışında herhangi bir şey için kullanılması önerilmez , bu da onları çirkin ve istenmeyen görünmelerini sağlamaktır, ancak bununla ilgili kötü bir şey yoktur, ancak, bunun static_castdaha güzel olması dışında .
underscore_d

0

Sunulan cevapların çoğunun sadece yerel kullanılmayan değişken için çalıştığını ve kullanılmayan statik global değişken için derleme hatasına neden olacağını buldum.

Kullanılmayan statik genel değişken uyarısını bastırmak için başka bir makro gerekiyordu.

template <typename T>
const T* UNUSED_VARIABLE(const T& dummy) { 
    return &dummy;
}
#define UNUSED_GLOBAL_VARIABLE(x) namespace {\
    const auto dummy = UNUSED_VARIABLE(x);\
}

static int a = 0;
UNUSED_GLOBAL_VARIABLE(a);

int main ()
{
    int b = 3;
    UNUSED_VARIABLE(b);
    return 0;
}

Anonim ad alanındaki statik olmayan genel değişken için hiçbir uyarı bildirilmediği için bu çalışır.

Yine de C ++ 11 gereklidir

 g++  -Wall -O3  -std=c++11 test.cpp

0

Lol! Kaos tarafından bozulan tüm heretikleri bu kadar iyi ortaya koyan SO üzerinde başka bir soru olduğunu sanmıyorum!

C ++ 17'ye gereken tüm saygıyla birlikte, C ++ Temel Yönergeleri'nde açık bir kılavuz vardır . AFAIR, 2009'da bu seçenek bugün olduğu gibi mevcuttu. Ve eğer birisi Doxygen'te bir böcek olarak kabul edildiğini söylüyorsa, Doxygen'te bir böcek var


-14

Uyarı ile ilgili sorununuzu görmüyorum. Xy derleyicisinin burada (doğru) bir uyarı vereceğini, ancak platform z için bu değişkenlerin gerekli olduğunu yöntem / işlev başlığında belgeleyin.

Uyarı doğrudur, kapatmanıza gerek yoktur. Programı geçersiz kılmaz - ancak bunun bir nedeni olduğu belgelenmelidir.


20
Sorun şu ki, yüzlerce veya binlerce böyle uyarınız varsa, yararlı olanı kaçırabilirsiniz. (İki kez, on binlerce uyarıyı gözden geçirmek, en fazla ortadan kaldırmak ve ciddi hatalara işaret eden birkaç gerçekten yararlı bulmak için durumdaydım.) Mümkünse en yüksek uyarı seviyesinde uyarılar olmadan derlemek her zaman iyidir.
sbi

4
Geçen yıl çalıştığım bir projede en yüksek uyarı seviyesini açtım ve ~ 10.000 uyarı aldım. Sadece birkaç düzine gerçekten yardımcı oldular. Bunlar arasında bir düzine gerçekten kötü hatalar gizlenmişti, ancak kod tabanını gerçekten birkaç ciddi olanı görebileceği noktaya kadar temizlemek birkaç hafta sürdü . Uyarı seviyesi her zaman yükselmiş ve kod tabanı uyarısız tutulmuş olsaydı, bu hatalar hiçbir zaman kodun içine girmezdi.
sbi

1
üzgünüm - ancak projenin sonlarında statik kod analizi yapmak (elinizdeki her hangi bir aracı, sadece derleyici olsa bile) yapmak biraz programın tamamını programlamak gibidir ve bitirdiğinizde, derlemeye basın ve hiçbir hatanız olmadığını umuyoruz.
Tobias Langner

2
@Richard: Binlerce kaynak dosyası olan projelerde çalıştım. Burada ve orada küçük bir uyarı, iyi belgelenmiş olanlar bile hızla ekleniyor. Bir derleme sırasında (yüzlerce veya binlerce yerine) yanıp sönen sadece düzinelerce uyarı olsa bile, yeni veya belgelenmiş olup olmadıklarını görmek için bunları tek tek aramak zorundasınız ve sonunda kazandı ' yapılmaz. Bunun için: Sıfır uyarı ile mümkün olan en yüksek uyarı seviyesinde derleyin. Ortaya çıkan her uyarı hemen fark edilecek, ona bakılacak ve düzeltilecek veya bastırılacaktır.
sbi

2
@sbi: derleyiciniz için en yüksek uyarı düzeyine dönmek, bir tür statik kod analizidir. Statik kod analizi, kodu çalıştırmadan okumak ve ondan bilgi çıkarmaktır. Derleyicinin kurallarını uyarılar için kontrol ederken yaptığı tam olarak budur.
Tobias Langner
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.