Birkaç kod satırı için GCC uyarıları nasıl devre dışı bırakılır


220

Visual C ++ ile kullanmak mümkündür #pragma warning (disable: ...). Ayrıca GCC'de dosya derleyici bayrakları başına geçersiz kılabileceğinizi buldum . Bunu "sonraki satır" için veya GCC kullanarak kod alanlarının çevresinde push / pop anlambilimiyle nasıl yapabilirim?


1
gcc'de belirli uyarıları devre dışı bırakmanın olası kopyası - Hata, aslında bu sorunun kendisi bir dupe (ancak kapalı değil). Bu sadece "İlgili" başlığı altında ortaya çıkan bir durumdur. Her neyse, bu SO üzerinde birkaç kez sorulmuş ve cevaplanmıştır.
Tyler McHenry

1
@paxdiablo: Ben tersini yapıyorum. Uyarı seviyesini çok yükselttim ve iyi olduğunu doğruladığım uyarıları satır satır ezmek istiyorum.
Matt Joiner

4
@Tyler McHenry: Daha dikkatli bir şekilde kontrol ettiyseniz, bağlantılı sorunun dosya başına bir çözüm içerdiğini, tam olarak kendi sorumda tatmin edici olarak bahsettiğimi (hatta bağlantıyı çaldım) not edebilirsiniz.
Matt Joiner

6
@paxdiablo, derleyiciler yanlış pozitif verir, bazen -Werror ile derlemek istersiniz, ancak bu yanlış pozitiflerin bir yapıyı engellemesini istemezsiniz. bu yüzden spesifik vakaları devre dışı bırakmak ve nedenini yorumlamak - bazı durumlarda mantıklıdır. Bunun kullanışlı olabileceği başka durumlar da var - içeri girmek ve değiştirmek çok kolay olmayan (kod üretildiğinden) zararsız uyarılar üreten otomatik oluşturma kodu gibi, ancak bu durumda dosya başına devre dışı bırakma olasılığı daha yüksek çözüm.
12:56

Yanıtlar:


221

Bu yapılabilir gibi görünüyor . Eklenen GCC sürümünü belirleyemiyorum, ancak Haziran 2010'dan bir süre önceydi.

İşte bir örnek:

#pragma GCC diagnostic error "-Wuninitialized"
    foo(a);         /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
    foo(b);         /* no diagnostic for this one */
#pragma GCC diagnostic pop
    foo(c);         /* error is given for this one */
#pragma GCC diagnostic pop
    foo(d);         /* depends on command line options */

14
bir pushve iki pops - pushbaşında başka bir eksik olabilir mi?
Abyss.7

37
"#pragma GCC tanılama push #pragma GCC tanılama pop GCC'nin her bir itme işleminden sonra tanılama durumunu hatırlamasına ve her bir pop'da bu noktaya geri dönmesine neden olur. Bir pop'un eşleşen itme yoksa, komut satırı seçenekleri geri yüklenir. " - GCC kılavuzundan: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul

11
Referans olarak, gcc 4.4.3 sürümü hata / uyarı /
yoksaymayı

12
Teşhis push / pop olan GCC'nin ilk versiyonu GCC 4.6.4'tür . Bunu GCC Dokümantasyonundaki
bitek

5
Bu uygulamada işe yaramaz bir utanç. Bazı durumlarda, daha fazla uyarı üretir. Ya da, daha doğrusu, GCC 4.7 ila 5.1 için pratikte çalışmaz. Örneğin bkz. GCC, uyarıları susturmak için 'pragma GCC teşhisi' ni onurlandırmaz .
jww

108

Her şeyi netleştirmek için, bu bir uyarıyı geçici olarak devre dışı bırakmanın bir örneğidir :

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
    write(foo, bar, baz);
#pragma GCC diagnostic pop

Daha fazla ayrıntı için teşhis uygulamaları hakkındaki GCC belgelerine bakabilirsiniz.


2
Çalışmalı ama benim gcc-4.9sadece bu çizgiyi tamamen görmezden geliyor.
Aleksei Petrenko

31

TL; DR : Bu gibi, kaçının veya kullanım belirteçleri çalışırsa __attribute__, aksi takdirde _Pragma.

Bu, GCC ve Clang'daki Uyarıları Gizleme adlı blog makalemin kısa bir sürümüdür .

Aşağıdakileri göz önünde bulundur Makefile

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

Aşağıdaki puts.ckaynak kodunu oluşturmak için

#include <stdio.h>

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

argcKullanılmadığı için derlenmeyecektir ve ayarlar serttir ( -W -Wall -pedantic -Werror).

Yapabileceğiniz 5 şey var:

  • Mümkünse kaynak kodunu iyileştirin
  • Gibi bir bildirim belirteci kullanın __attribute__
  • kullanım _Pragma
  • kullanım #pragma
  • Bir komut satırı seçeneği kullanın.

Kaynağın iyileştirilmesi

İlk deneme, uyarıdan kurtulmak için kaynak kodunun iyileştirilip iyileştirilemeyeceğini kontrol etmek olmalıdır. Bu durumda ( son öğeden sonra) argcolduğu gibi algoritmayı da bu nedenle değiştirmek istemiyoruz .!*argvNULL

Gibi bir bildirim belirteci kullanma __attribute__

#include <stdio.h>

int main(__attribute__((unused)) int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

Şanslıysanız, standart durumunuz için bir belirteç sağlar _Noreturn.

__attribute__tescilli GCC uzantısıdır (Clang ve diğer bazı derleyiciler tarafından desteklenir armcc) ve diğer birçok derleyici tarafından anlaşılmayacaktır. __attribute__((unused))Taşınabilir kod istiyorsanız bir makronun içine koyun .

_Pragma Şebeke

_Pragmaalternatif olarak kullanılabilir #pragma.

#include <stdio.h>

_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}
_Pragma("GCC diagnostic pop")

_PragmaOperatörün ana avantajı , #pragmadirektif ile mümkün olmayan makroların içine yerleştirebilmenizdir .

Dezavantajı: Beyana dayalı yerine satır tabanlı çalıştığı için neredeyse taktiksel bir nuke.

_PragmaOperatör C99 tanıtıldı.

#pragma direktif.

Bir kod bölgesi, genellikle bir işlev için uyarıyı bastırmak için kaynak kodunu değiştirebiliriz:

#include <stdio.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
int main(int argc, const char *argv[])
{
    while (*++argc) puts(*argv);
    return 0;
}
#pragma GCC diagnostic pop

Dezavantajı: Beyana dayalı yerine satır tabanlı çalıştığı için neredeyse taktiksel bir nuke.

Clang'da benzer bir sözdiziminin bulunduğunu unutmayın .

Tek bir dosya için komut satırındaki uyarıyı gizleme

Özellikle Makefilekoyarlar için uyarıyı bastırmak için aşağıdaki satırı ekleyebiliriz :

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.o: CPPFLAGS+=-Wno-unused-parameter

Bu muhtemelen sizin özel durumunuzda olmasını istemez, ancak benzer durumlarda olan diğer okumalara yardımcı olabilir.


2
re: argümana bir isim vermeyerek improving the sourcemain bildirimini değiştirmek için de işe yarayacaktır int main(int, const char* argv[]) { ... }, derleyiciye kullanılmayacağını söylersiniz.
Jesse Chisholm

1
@JesseChisholm işlev tanımında parametre adını atlamak mümkün değildir. ISO / IEC9899 arasında 6.9.1 Fonksiyon definintions bakın, § 5. Ve doğru yüzden kod tarafından reddedilse "Bildiricisi bir parametre türü listesini içerir, her parametrenin beyanı bir tanımlayıcı [...] içerecektir" gccyanı sıra clang.
Christian Hujer

1
Başka bir örüntü, sadece değişkenin bir dökümünü geçersiz kılmaktır. Aslında, bir projede şu makroyu gördüm: #define UNUSED(x) ((void)x)Uyarıları susturmak için kullanılır. Sanırım ReactOS'ta mıydı?
Paul Stelian

1
Bundan sonra ters eğik çizgiye ihtiyacınız olduğunu düşünmüyorum, değil mi? _Pragma("GCC diagnostic pop") \ sadece _Pragma("GCC diagnostic pop")bence olmalı .
Gabriel Staples

1
@GabrielStaples Doğru, fark ettiğiniz için teşekkürler, cevabı güncelledim.
Christian Hujer

20
#define DIAG_STR(s) #s
#define DIAG_JOINSTR(x,y) DIAG_STR(x ## y)
#ifdef _MSC_VER
#define DIAG_DO_PRAGMA(x) __pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(warning(x))
#else
#define DIAG_DO_PRAGMA(x) _Pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(compiler diagnostic x)
#endif
#if defined(__clang__)
# define DISABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,push) DIAG_PRAGMA(clang,ignored DIAG_JOINSTR(-W,clang_option))
# define ENABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,pop)
#elif defined(_MSC_VER)
# define DISABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,push) DIAG_DO_PRAGMA(warning(disable:##msvc_errorcode))
# define ENABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,pop)
#elif defined(__GNUC__)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,push) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,pop)
#else
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_option,msvc_unused) DIAG_PRAGMA(GCC,warning DIAG_JOINSTR(-W,gcc_option))
#endif
#endif

Bu gcc, clang ve msvc için hile yapmalıdır

Örneğin ile çağrılabilir:

DISABLE_WARNING(unused-variable,unused-variable,42)
[.... some code with warnings in here ....]
ENABLE_WARNING(unused-variable,unused-variable,42)

bkz. https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html , http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas ve https://msdn.microsoft .com / de-DE / kütüphane / d9x1s805.aspx daha fazla bilgi için

Gcc için bu tür pragmaları kullanmak için en az 4.02 sürümüne ihtiyacınız var, msvc ve clang sürümleri hakkında emin değilsiniz.

Gcc için itme pop pragma taşıma biraz kırık gibi görünüyor. Uyarıyı tekrar etkinleştirirseniz, DISABLE_WARNING / ENABLE_WARNING bloğunun içindeki blok için uyarıyı almaya devam edersiniz. Gcc'nin bazı sürümleri için çalışır, bazıları için çalışmaz.


3
Sen da gerçek MVP
zeboidlund


6

ROS başlıkları gibi harici kütüphanelerde de aynı sorunu yaşadım. Daha sıkı derleme için CMakeLists.txt dosyasında aşağıdaki seçenekleri kullanmayı seviyorum:

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wextra -Wstrict-aliasing -pedantic -Werror -Wunreachable-code ${CMAKE_CXX_FLAGS}")

Ancak bunu yapmak, harici olarak dahil edilen kütüphanelerde de her türlü bilgiçlik hatasına neden olur. Çözüm, harici kitaplıkları eklemeden ve aşağıdaki gibi yeniden etkinleştirmeden önce tüm bilgiçlik uyarılarını devre dışı bırakmaktır:

//save compiler switches
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"

//Bad headers with problem goes here
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>

//restore compiler switches
#pragma GCC diagnostic pop

2
Bunun gcc'nin sistem dizinleri ile daha iyi ele alınmaması gerekir mi?
Kırmızı XIII

@RedXIII - evet, bu dizinlerin listesini yapabilir ve gcc komut satırında belirtebiliyorsanız bu bir seçenektir. Ancak birçok kez derleyici boru hattının derinliklerinde çağrılır veya başka birinin kodunuzu nasıl derlemesi gerektiği konusunda çok fazla kontrolünüz yoktur. Yukarıdaki durumlarda muhtemelen daha iyi bir çözümdür.
Shital Shah

5

Sorunun GCC ile ilgili olduğunu biliyorum, ancak bunu diğer ve / veya çoklu derleyicilerde nasıl yapacağını arayanlar için…

TL; DR

Sizin için bu şeylerin çoğunu yapan bir kamu malı tek C / C ++ başlığı olan Hedley'ye bir göz atmak isteyebilirsiniz . Bu yazının sonunda Hedley'nin tüm bunlar için nasıl kullanılacağı hakkında hızlı bir bölüm koyacağım.

Uyarıyı devre dışı bırakma

#pragma warning (disable: …) çoğu derleyicide eşdeğerleri vardır:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…"burada üç nokta uyarının adıdır; örneğin , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • clang: #pragma clang diagnostic ignored "-W…". Sözdizimi temel olarak GCC'lerle aynıdır ve uyarı adlarının çoğu aynıdır (çoğu olmasa da).
  • Intel C Derleyici: MSVC sözdizimini kullanın, ancak uyarı numaralarının tamamen farklı olduğunu unutmayın. Örnek: #pragma warning(disable:1478 1786).
  • PGI: Bir diag_suppresspragma var:#pragma diag_suppress 1215,1444
  • TI: diag_suppressPGI ile aynı sözdizimine (ancak farklı uyarı numaralarına!) Sahip bir pragma var:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): bir error_messagespragma var. Rahatsız edici bir şekilde, C ve C ++ derleyicileri için uyarılar farklıdır. Bunların her ikisi de temelde aynı uyarıları devre dışı bırakır:
    • C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: diag_suppressPGI ve TI gibi de kullanır , ancak sözdizimi farklıdır. Uyarı numaralarından bazıları aynı, ancak ben diğerlerinden ayrıldım:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: MSVC'ye benzer, ancak yine sayılar farklı #pragma warn(disable:2241)

Çoğu derleyici için, derleyici sürümünü devre dışı bırakmadan önce kontrol etmek genellikle iyi bir fikirdir, aksi takdirde başka bir uyarıyı tetiklersiniz. Örneğin, GCC 7 -Wimplicit-fallthroughuyarı için destek eklediğinden, 7'den önce GCC'yi önemsiyorsanız, şöyle bir şey yapmalısınız

#if defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Daha yeni XL C / C ++ ve armclang gibi clang tabanlı clang ve derleyiciler için, derleyicinin __has_warning()makroyu kullanarak belirli bir uyarıyı bilip bilmediğini kontrol edebilirsiniz .

#if __has_warning("-Wimplicit-fallthrough")
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif

Tabii ki __has_warning()makronun var olup olmadığını da kontrol etmelisiniz :

#if defined(__has_warning)
#  if __has_warning("-Wimplicit-fallthrough")
#    pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#  endif
#endif

Böyle bir şey yapmaya cazip olabilirsiniz

#if !defined(__has_warning)
#  define __has_warning(warning)
#endif

Böylece __has_warningbiraz daha kolay kullanabilirsiniz. Clang, kılavuzlarındaki __has_builtin()makro için benzer bir şey bile öneriyor . Bunu yapma . Diğer kodlar, __has_warningderleyici sürümlerini denetleyip denetleyebilir ve eğer tanımlamazsanız __has_warning, kodlarını kıracaksınız. Bunu yapmanın doğru yolu, ad alanınızda bir makro oluşturmaktır. Örneğin:

#if defined(__has_warning)
#  define MY_HAS_WARNING(warning) __has_warning(warning)
#else
#  define MY_HAS_WARNING(warning) (0)
#endif

Sonra gibi şeyler yapabilirsiniz

#if MY_HAS_WARNING(warning)
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#elif defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

İtme ve haşhaş

Birçok derleyici, uyarıları yığının üzerine itme ve açma yolunu da destekler. Örneğin, bu, bir kod satırı için GCC'de bir uyarıyı devre dışı bırakır ve ardından önceki durumuna döndürür:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
call_deprecated_function();
#pragma GCC diagnostic pop

Tabii ki derleyiciler arasında sözdizimi hakkında çok fazla anlaşma yok:

  • GCC 4.6+: #pragma GCC diagnostic push /#pragma GCC diagnostic pop
  • clang: #pragma clang diagnostic push /#pragma diagnostic pop
  • Intel 13+ (ve muhtemelen daha önce): #pragma warning(push) /#pragma warning(pop)
  • MSVC 15+ (VS 9.0 / 2008): #pragma warning(push) /#pragma warning(pop)
  • ARM 5.6+: #pragma push /#pragma pop
  • TI 8.1+: #pragma diag_push /#pragma diag_pop
  • Pelles C 2.90+ (ve muhtemelen daha önce): #pragma warning(push) /#pragma warning(pop)

Bellek hizmet veriyorsa, GCC'nin bazı çok eski sürümleri için (3.x, IIRC gibi) push / pop pragmaları işlevin dışında .

Kanlı ayrıntılarını gizleme

Çoğu derleyici için _Pragma, C99'da tanıtılan makroların arkasındaki mantığı gizlemek mümkündür . C99 olmayan modda bile, çoğu derleyici destekler _Pragma; büyük istisna, __pragmafarklı bir sözdizimine sahip kendi anahtar kelimesi olan MSVC'dir. Standart _Pragmabir dize alır, Microsoft sürümü şunları yapmaz:

#if defined(_MSC_VER)
#  define PRAGMA_FOO __pragma(foo)
#else
#  define PRAGMA_FOO _Pragma("foo")
#endif
PRAGMA_FOO

Ön işlemden geçirildikten sonra kabaca eşdeğerdir.

#pragma foo

Bu, makrolar oluşturmamızı sağlar, böylece kod yazabiliriz

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

Ve makro tanımlarındaki çirkin sürüm kontrollerini gizleyin.

Kolay yol: Hedley

Artık kodunuzu temiz tutarken böyle şeyleri nasıl taşınabilir yapmanın mekaniğini anladığınıza göre, projelerimden biri olan Hedley'nin ne yaptığını anlıyorsunuz . Tonlarca belgeyi incelemek ve / veya test edebildiğiniz kadar çok derleyicinin birçok sürümünü yüklemek yerine, Hedley'yi (tek bir kamu malı C / C ++ başlığıdır) dahil edebilir ve onunla yapabilirsiniz. Örneğin:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles ve muhtemelen diğerlerinde kullanımdan kaldırılmış bir işlevi çağırmayla ilgili uyarıyı devre dışı bırakacaktır (Hedley'i güncellerken muhtemelen bu cevabı güncellemekten rahatsız olmayacağım). Ayrıca, çalışması bilinmeyen derleyicilerde, makrolar hiçbir şeye önceden işlenmeyecektir, bu nedenle kodunuz herhangi bir derleyici ile çalışmaya devam edecektir. Elbette HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDHedley'in bildiği tek uyarı değildir ve tüm Hedley'in yapabileceği uyarıları devre dışı bırakmaz, ancak umarım bu fikri anlarsınız.


3

Uyarıları susturmak yerine, gcc stili genellikle __attribute__derleyiciye niyetiniz hakkında daha fazla bilgi vermek için standart C yapılarını veya uzantısını kullanmaktır. Örneğin, koşul olarak kullanılan atamayla ilgili uyarı, atamanın parantez içine alınmasıyla, yani if ((p=malloc(cnt)))yerine bastırılır if (p=malloc(cnt)). Kullanılmayan işlev argümanları ile ilgili uyarılar __attribute__, asla hatırlayamadığım bazı garip veya kendi kendine atama vb.


2
Belki bu yüzden. Amacım herhangi bir genel vaka modelini kanıtlamak değil, gcc'nin uyarı bastırma felsefesinin ne olduğuna dair bir gözlem.
R .. GitHub BUZA YARDIMCI DURDUR

derleyici eklenen parantez ile w / r / t uyarıları farklı davranır?!?! ?? !!!! VAOV! Bu beklenmedik bir şey.
Jason S

1
@JasonS parens, uyarıların derleyicinin davranışını değiştirmez, yaptığı şey ifadenin anlamını değiştirmektir. Ekstra parens, derleyicinin ödevi bitirmesini ve son değerini bir uyarı olarak tutmasını sağlar, bu da hiçbir uyarıyı hak etmez. Netlik istiyorsanız if ((p=malloc(cnt)) != NULL) ..., derleyicinin perde arkasında yaptığı şey budur.
Jesse Chisholm

@ JesseChisholm: Açıklamanızın doğru olduğunu düşünmüyorum.
R .. GitHub BUZA YARDIMCI DURDUR

3

Bu sayfayı IAR'de yapmanın bir yolunu arayanlar için şunu deneyin:

#pragma diag_suppress=Pe177
void foo1( void )
{
   /* The following line of code would normally provoke diagnostic 
      message #177-D: variable "x" was declared but never referenced.
      Instead, we have suppressed this warning throughout the entire 
      scope of foo1(). 
   */
   int x;
}
#pragma diag_default=Pe177

Görmek Referans için http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html adresine .

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.