วิธีปิดการใช้งานคำเตือนของ GCC สำหรับรหัสสองสามบรรทัด


220

ใน Visual C ++ #pragma warning (disable: ...)มันเป็นไปได้ที่จะใช้งาน นอกจากนี้ผมพบว่าใน GCC คุณสามารถแทนที่ต่อธงคอมไพเลอร์ไฟล์ ฉันจะทำสิ่งนี้สำหรับ "บรรทัดถัดไป" หรือด้วยความหมายของพุช / ป๊อปรอบ ๆ พื้นที่ของรหัสโดยใช้ GCC ได้อย่างไร


1
ซ้ำซ้อนที่เป็นไปได้ของการปิดการใช้งานคำเตือนที่เฉพาะเจาะจงใน gcc - โอ๊ะจริง ๆ แล้วคำถามนั้นเองคือ dupe (แต่ไม่ปิด) นั่นเพิ่งเกิดขึ้นกับสิ่งที่ปรากฏภายใต้ "ที่เกี่ยวข้อง" อย่างไรก็ตามมีการถามและตอบคำถามนี้หลายครั้ง
Tyler McHenry

1
@paxdiablo: ฉันทำเครื่องหมายย้อนกลับ ฉันตั้งค่าระดับการเตือนสูงขึ้นมากและต้องการกำจัดคำเตือนทีละบรรทัดที่ฉันยืนยันแล้วว่าไม่เป็นไร
Matt Joiner

4
@Tyler McHenry: หากคุณตรวจสอบอย่างละเอียดมากขึ้นคุณอาจทราบว่าคำถามที่เชื่อมโยงนั้นมีคำตอบต่อไฟล์นั่นคือคำถามที่ฉันพูดถึงในคำถามของฉันเองว่าไม่น่าพอใจ (ฉันขโมยลิงก์)
Matt Joiner

6
@paxdiablo คอมไพเลอร์ให้ค่าบวกเท็จบางครั้งคุณต้องการคอมไพล์ด้วย -Werror แต่ไม่มีการบวกที่เป็นเท็จเหล่านี้บล็อกการสร้าง ดังนั้นการปิดใช้งานกรณีที่มีการเสแสร้งและการแสดงความคิดเห็นว่าทำไม - เหมาะสมในบางกรณี มีอีกหลายกรณีที่สิ่งนี้มีประโยชน์ - เช่นรหัสการสร้างอัตโนมัติที่สร้างคำเตือนที่ไม่เป็นอันตรายซึ่งไม่ง่ายที่จะเข้าไปและเปลี่ยนแปลง (ตั้งแต่สร้างรหัส) แม้ว่าในกรณีนั้นการปิดใช้งานต่อไฟล์จะมีแนวโน้มมากกว่า การแก้ไขปัญหา.
ideasman42

คำตอบ:


221

มันจะปรากฏขึ้นนี้สามารถทำได้ ฉันไม่สามารถระบุรุ่นของ GCC ที่เพิ่มเข้ามาได้ แต่ก่อนหน้านี้บางครั้งก่อนเดือนมิถุนายน 2010

นี่คือตัวอย่าง:

#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
หนึ่งpushและสองpops - อาจเป็นอีกpushจุดเริ่มต้นหายไป?
abyss.7

37
"#pragma GCC การพุชการวินิจฉัย #pragma GCC ป็อปอัพการวินิจฉัยทำให้ GCC จดจำสถานะการวินิจฉัยของแต่ละการพุชและเรียกคืนไปยังจุดนั้นในแต่ละป๊อปหากป๊อปไม่มีการพุชที่ตรงกันตัวเลือกบรรทัดคำสั่งจะถูกกู้คืน " - จากคู่มือ GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul

11
สำหรับการอ้างอิง gcc เวอร์ชั่น 4.4.3 รองรับข้อผิดพลาด / คำเตือน / เพิกเฉย แต่ไม่ใช่การพุช / ป๊อป
frankster

12
รุ่นแรกของ GCC ที่มีการวินิจฉัยผลัก / ป๊อปเป็นGCC 4.6.4 ผมตั้งใจไว้โดยดูที่ส่วนการวินิจฉัย-Pragmas.html # วินิจฉัย-pragmas สำหรับแต่ละรุ่น GCC ที่GCC เอกสาร
bitek

5
มันเป็นความอัปยศที่มันใช้ไม่ได้ในทางปฏิบัติ ในบางกรณีจะสร้างคำเตือนเพิ่มเติม หรืออาจมากกว่าอย่างถูกต้องมันไม่ทำงานในทางปฏิบัติสำหรับ GCC 4.7 ถึง 5.1 ดูตัวอย่างเช่นGCC ไม่ให้เกียรติ 'pragma GCC วินิจฉัย' คำเตือนความเงียบ
jww

108

หากต้องการรวมทุกอย่างออกมานี่เป็นตัวอย่างของการปิดใช้งานคำเตือนชั่วคราว :

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

คุณสามารถตรวจสอบเอกสาร GCC เกี่ยวกับการวินิจฉัยเพื่อดูรายละเอียดเพิ่มเติม


2
ควรใช้งานได้ แต่ฉันgcc-4.9ไม่สนใจบรรทัดนี้อย่างสมบูรณ์
Aleksei Petrenko

31

TL; DR : หากการทำงานหลีกเลี่ยงหรือใช้ specifiers ชอบมิฉะนั้น__attribute___Pragma

นี่เป็นบทความสั้น ๆ ในบล็อกของฉัน การระงับคำเตือนใน GCC และเสียงดังกราว

พิจารณาดังต่อไปนี้ Makefile

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

.PHONY: all
all: puts

สำหรับการสร้างputs.cซอร์สโค้ดต่อไปนี้

#include <stdio.h>

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

มันจะไม่รวบรวมเพราะargcไม่ได้ใช้และการตั้งค่าจะไม่ยอมใครง่ายๆ ( -W -Wall -pedantic -Werror)

มี 5 สิ่งที่คุณสามารถทำได้:

  • ปรับปรุงซอร์สโค้ดถ้าเป็นไปได้
  • ใช้ตัวระบุการประกาศเช่น __attribute__
  • ใช้ _Pragma
  • ใช้ #pragma
  • ใช้ตัวเลือกบรรทัดคำสั่ง

ปรับปรุงแหล่งที่มา

ความพยายามครั้งแรกควรตรวจสอบว่าสามารถปรับปรุงซอร์สโค้ดเพื่อกำจัดคำเตือนได้หรือไม่ ในกรณีนี้เราไม่ต้องการเปลี่ยนอัลกอริทึมเพียงเพราะสิ่งนั้นเช่นเดียวargcกับที่ซ้ำซ้อนกับ!*argv( NULLหลังจากองค์ประกอบสุดท้าย)

การใช้ตัวระบุการประกาศเช่น __attribute__

#include <stdio.h>

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

_Noreturnถ้าคุณโชคดีมาตรฐานให้ระบุสำหรับสถานการณ์ของคุณเช่น

__attribute__เป็นส่วนขยาย GCC ที่เป็นกรรมสิทธิ์ (สนับสนุนโดย Clang และคอมไพเลอร์อื่น ๆ เช่นarmccกัน) และจะไม่สามารถเข้าใจได้โดยคอมไพเลอร์อื่น ๆ ใส่__attribute__((unused))ในแมโครถ้าคุณต้องการโค้ดแบบพกพา

_Pragma ผู้ประกอบการ

_Pragma#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")

ข้อได้เปรียบหลักของ_Pragmaโอเปอเรเตอร์คือคุณสามารถใส่ไว้ในมาโครซึ่งไม่สามารถทำได้ด้วย#pragmaคำสั่ง

ข้อเสีย: มันเกือบจะเป็นยุทธวิธีนูคเพราะมันทำงานแบบ line-based แทนการประกาศตาม

_Pragmaผู้ประกอบการได้รับการแนะนำใน C99

#pragma คำสั่ง

เราสามารถเปลี่ยนซอร์สโค้ดเพื่อไม่ให้มีการเตือนสำหรับส่วนของโค้ดซึ่งโดยทั่วไปจะเป็นฟังก์ชั่นทั้งหมด:

#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

ข้อเสีย: มันเกือบจะเป็นยุทธวิธีนูคเพราะมันทำงานแบบ line-based แทนการประกาศตาม

โปรดทราบว่าไวยากรณ์ที่คล้ายกันอยู่ในเสียงดังกราว

หยุดการเตือนบนบรรทัดคำสั่งสำหรับไฟล์เดียว

เราสามารถเพิ่มบรรทัดต่อไปนี้ในMakefileการระงับคำเตือนโดยเฉพาะสำหรับการใส่:

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

.PHONY: all
all: puts

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

นี่อาจไม่ต้องการให้คุณต้องการในกรณีเฉพาะของคุณ แต่มันอาจช่วยให้ผู้อ่านคนอื่น ๆ ที่อยู่ในสถานการณ์ที่คล้ายกัน


2
Re: improving the sourceมันจะทำงานเพื่อเปลี่ยนการประกาศของ main int main(int, const char* argv[]) { ... }โดยไม่ให้อาร์กิวเมนต์ชื่อคุณบอกคอมไพเลอร์ว่ามันจะไม่ได้ใช้
Jesse Chisholm

1
@JesseChisholm ไม่ใช้ชื่อพารามิเตอร์ที่นิยามฟังก์ชันเป็นไปไม่ได้ ดู 6.9.1 ฟังก์ชั่น definintions ของ ISO / IEC9899, §5 "ถ้า declarator รวมถึงรายการประเภทพารามิเตอร์การประกาศของแต่ละพารามิเตอร์จะรวมตัวระบุ [ ... ]" และถูกต้องเพื่อรหัสจะได้รับการปฏิเสธโดยตลอดจนgcc clang
Christian Hujer

1
อีกรูปแบบหนึ่งก็คือการทำการโยนตัวแปรให้เป็นโมฆะ อันที่จริงฉันเห็นมาโครในโปรเจ็กต์ต่อไปนี้: #define UNUSED(x) ((void)x)ใช้เพื่อปิดเสียงคำเตือน ฉันคิดว่ามันเป็นใน ReactOS?
Paul Stelian

1
ฉันไม่คิดว่าคุณต้องการแบ็กสแลชหลังจากนี้ใช่ไหม ฉัน_Pragma("GCC diagnostic pop") \ ควรจะเป็น_Pragma("GCC diagnostic pop")อย่างนั้น
Gabriel Staples

1
@GabrielStaples ถูกต้องขอบคุณที่สังเกตฉันได้อัปเดตคำตอบแล้ว
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

สิ่งนี้ควรทำเคล็ดลับสำหรับ gcc, clang และ msvc

สามารถเรียกด้วยเช่น:

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

ดูhttps://gcc.gnu.org/onlinedocs/cpp/Pragmas.html , http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmasและhttps://msdn.microsoft .com / de-DE / library / d9x1s805.aspxสำหรับรายละเอียดเพิ่มเติม

คุณต้องการอย่างน้อยรุ่น 4.02 เพื่อใช้ pragmas ประเภทนี้สำหรับ gcc ไม่แน่ใจเกี่ยวกับ msvc และ clang เกี่ยวกับเวอร์ชัน

ดูเหมือนว่าการกดปุ่มป๊อปอัปการจัดการสำหรับ gcc จะหักนิดหน่อย หากคุณเปิดใช้งานคำเตือนอีกครั้งคุณจะยังคงได้รับคำเตือนสำหรับบล็อกที่อยู่ในบล็อค DISABLE_WARNING / ENABLE_WARNING สำหรับ gcc บางรุ่นใช้งานได้สำหรับบางรุ่นใช้ไม่ได้


3
คุณเป็น MVP จริง
zeboidlund

19
#pragma GCC diagnostic ignored "-Wformat"

แทนที่ "-Watat" ด้วยชื่อของธงเตือนของคุณ

AFAIK ไม่มีวิธีใช้การกด / ป๊อปอรรถศาสตร์สำหรับตัวเลือกนี้


4
มันเป็นความอัปยศที่มันใช้ไม่ได้ในทางปฏิบัติ ในบางกรณีจะสร้างคำเตือนเพิ่มเติม หรืออาจมากกว่าอย่างถูกต้องมันไม่ทำงานในทางปฏิบัติสำหรับ GCC 4.7 ถึง 5.1 ดูตัวอย่างเช่นGCC ไม่ให้เกียรติ 'pragma GCC วินิจฉัย' คำเตือนความเงียบ
jww

6

ฉันมีปัญหาเดียวกันกับห้องสมุดภายนอกเช่นส่วนหัวของ ROS ฉันต้องการใช้ตัวเลือกต่อไปนี้ใน CMakeLists.txt สำหรับการรวบรวมที่เข้มงวดยิ่งขึ้น:

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

อย่างไรก็ตามการทำเช่นนี้ทำให้เกิดข้อผิดพลาดทางอารมณ์ทุกประเภทในห้องสมุดที่รวมอยู่ภายนอกเช่นกัน วิธีแก้ไขคือปิดการใช้งานคำเตือนแบบ pedantic ทั้งหมดก่อนที่จะรวมไลบรารี่ภายนอกและเปิดใช้งานเช่นนี้:

//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
สิ่งนี้ควรจัดการกับไดเรกทอรีระบบ ของ gcc หรือไม่
Red XIII

@RedXIII - ใช่นั่นคือตัวเลือกถ้าคุณสามารถทำรายการไดเรกทอรีดังกล่าวและระบุในบรรทัดคำสั่ง gcc อย่างไรก็ตามหลายครั้งที่คอมไพเลอร์ถูกเรียกใช้อย่างลึกเข้าไปใน Pipeline หรือคุณไม่สามารถควบคุมว่าคนอื่นควรรวบรวมรหัสของคุณอย่างไร ในกรณีข้างต้นอาจเป็นทางออกที่ดีกว่า
Shital Shah

5

ฉันรู้ว่าคำถามนั้นเกี่ยวกับ GCC แต่สำหรับคนที่กำลังมองหาวิธีการทำสิ่งนี้ในคอมไพเลอร์อื่น ๆ และ / หรือหลายคอมไพเลอร์ ...

TL; DR

คุณอาจต้องการที่จะดูHedleyซึ่งเป็นส่วนหัว C / C ++ เดียวโดเมนสาธารณะที่ฉันเขียนซึ่งไม่มากของสิ่งนี้สำหรับคุณ ฉันจะพูดอย่างย่อเกี่ยวกับวิธีใช้ Hedley สำหรับทั้งหมดนี้ในตอนท้ายของโพสต์นี้

ปิดการใช้งานคำเตือน

#pragma warning (disable: …) มีความเท่าเทียมกันในคอมไพเลอร์ส่วนใหญ่:

  • MSVC: #pragma warning(disable:4996)
  • GCC: #pragma GCC diagnostic ignored "-W…"จุดไข่ปลาเป็นชื่อของคำเตือน; เช่น#pragma GCC diagnostic ignored "-Wdeprecated-declarations ,
  • #pragma clang diagnostic ignored "-W…"เสียงดังกราว: ไวยากรณ์นั้นโดยทั่วไปเหมือนกับของ GCC และชื่อคำเตือนจำนวนมากเหมือนกัน (แม้ว่าจะไม่มาก)
  • Intel C Compiler: ใช้ไวยากรณ์ MSVC แต่โปรดจำไว้ว่าหมายเลขคำเตือนต่างออกไปโดยสิ้นเชิง ตัวอย่าง:#pragma warning(disable:1478 1786) .
  • PGI: มี diag_suppress :#pragma diag_suppress 1215,1444
  • TI: มี diag_suppress pragma ที่มีไวยากรณ์เดียวกัน (แต่มีคำเตือนต่างกัน!) กับ PGI:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): มีความerror_messagesหมาย น่ารำคาญคำเตือนต่างกันสำหรับคอมไพเลอร์ C และ C ++ ทั้งสองอย่างนี้ปิดการใช้งานโดยทั่วไปคำเตือนเดียวกัน
    • ค: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: ใช้diag_suppressเหมือน PGI และ TI แต่ไวยากรณ์แตกต่างกัน ตัวเลขคำเตือนบางอย่างเหมือนกัน แต่คนอื่น ๆ ก็แยกกัน:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: คล้ายกับ MSVC แม้ว่าตัวเลขจะแตกต่างกันอีกครั้ง #pragma warn(disable:2241)

สำหรับคอมไพเลอร์ส่วนใหญ่มักจะเป็นความคิดที่ดีที่จะตรวจสอบเวอร์ชั่นคอมไพเลอร์ก่อนที่จะลองปิดการใช้งานมิฉะนั้นคุณจะจบลงด้วยการเรียกคำเตือนอื่น ตัวอย่างเช่น GCC 7 เพิ่มการสนับสนุนสำหรับ-Wimplicit-fallthroughคำเตือนดังนั้นหากคุณสนใจ GCC ก่อน 7 คุณควรทำอะไรเช่นนี้

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

สำหรับ clang และ compilers ที่ใช้ clang เช่น XL C / C ++ และ armclang เวอร์ชันใหม่กว่าคุณสามารถตรวจสอบว่าคอมไพเลอร์รู้เกี่ยวกับคำเตือนเฉพาะที่ใช้__has_warning()แมโครหรือไม่

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

แน่นอนคุณต้องตรวจสอบเพื่อดูว่ามี__has_warning()แมโครอยู่หรือไม่:

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

คุณอาจถูกล่อลวงให้ทำสิ่งที่ชอบ

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

เพื่อให้คุณสามารถใช้งาน__has_warningได้ง่ายขึ้น เสียงดังยังแนะนำสิ่งที่คล้ายกันสำหรับ__has_builtin()มาโครในคู่มือ อย่าทำอย่างนี้ รหัสอื่นอาจตรวจสอบ__has_warningและย้อนกลับไปที่การตรวจสอบเวอร์ชันคอมไพเลอร์หากไม่มีอยู่และถ้าคุณกำหนดว่า__has_warningคุณจะทำผิดรหัส วิธีที่ถูกต้องในการทำเช่นนี้คือการสร้างมาโครในเนมสเปซของคุณ ตัวอย่างเช่น:

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

จากนั้นคุณสามารถทำสิ่งต่าง ๆ เช่น

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

ผลักดันและ popping

คอมไพเลอร์จำนวนมากยังสนับสนุนวิธีในการพุชและป๊อปคำเตือนลงบนสแต็ก ตัวอย่างเช่นสิ่งนี้จะปิดการใช้งานคำเตือนใน GCC สำหรับรหัสหนึ่งบรรทัดจากนั้นกลับสู่สถานะก่อนหน้า:

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

แน่นอนมีข้อตกลงไม่มากนักในคอมไพเลอร์เกี่ยวกับไวยากรณ์:

  • GCC 4.6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • เสียงดังกราว: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (และอาจเร็วกว่านี้): #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+ (และอาจเร็วกว่านี้): #pragma warning(push)/#pragma warning(pop)

หากหน่วยความจำทำหน้าที่สำหรับ GCC รุ่นเก่า (เช่น 3.x, IIRC) บางรุ่น push / pop pragmas ต้องอยู่นอกฟังก์ชั่น

ซ่อนรายละเอียดเต็มไปด้วยเลือด

สำหรับคอมไพเลอร์ส่วนใหญ่สามารถซ่อนตรรกะเบื้องหลังมาโครที่ใช้_Pragmaซึ่งเปิดตัวใน C99 แม้จะอยู่ในโหมดที่ไม่ใช่ C99 คอมไพเลอร์ส่วนใหญ่สนับสนุน_Pragma; ข้อยกเว้นใหญ่คือ MSVC ซึ่งมี__pragmaคำหลักของตัวเองที่มีไวยากรณ์ที่แตกต่างกัน มาตรฐาน_Pragmaใช้สายอักขระเวอร์ชันของ Microsoft ไม่ได้:

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

เทียบเท่าโดยประมาณเมื่อประมวลผลล่วงหน้าแล้วเป็น

#pragma foo

สิ่งนี้ช่วยให้เราสร้างมาโครเพื่อให้เราสามารถเขียนโค้ดได้

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

และซ่อนการตรวจสอบเวอร์ชั่นที่น่าเกลียดทั้งหมดในนิยามแมโคร

วิธีง่ายๆ: Hedley

ตอนนี้คุณเข้าใจกลไกของวิธีการที่จะทำสิ่งเช่นนี้ portably ขณะที่การรักษารหัสของคุณสะอาดคุณเข้าใจสิ่งหนึ่งในโครงการของฉันHedleyไม่ แทนที่จะขุดผ่านเอกสารจำนวนมากและ / หรือติดตั้งคอมไพเลอร์ให้มากเท่าที่คุณสามารถทำการทดสอบได้คุณสามารถใส่ Hedley (เป็นโดเมนสาธารณะส่วนหัว C / C ++ เดียว) และทำได้ด้วย ตัวอย่างเช่น:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

จะปิดการใช้งานคำเตือนเกี่ยวกับการเรียกใช้ฟังก์ชันที่เลิกใช้แล้วใน GCC, เสียงดังกราว, ICC, PGI, MSVC, TI, IAR, ODS, Pelles และอื่น ๆ และในคอมไพเลอร์ที่ไม่ทราบว่าใช้งานได้มาโครนั้นจะถูกประมวลผลล่วงหน้าเป็นอะไรเลยดังนั้นโค้ดของคุณจะทำงานร่วมกับคอมไพเลอร์ต่อไป แน่นอนว่าHEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDไม่ใช่คำเตือนเพียงอย่างเดียวที่ Hedley รู้และไม่ได้ปิดใช้งานคำเตือนทั้งหมดที่ Hedley สามารถทำได้ แต่หวังว่าคุณจะได้รับแนวคิดนี้


3

แทนที่จะเงียบคำเตือนสไตล์ gcc มักจะใช้โครงสร้าง C มาตรฐานหรือ__attribute__ส่วนขยายเพื่อบอกคอมไพเลอร์เพิ่มเติมเกี่ยวกับความตั้งใจของคุณ ยกตัวอย่างเช่นคำเตือนเกี่ยวกับการกำหนดใช้เป็นสภาพที่ถูกระงับโดยการวางที่ได้รับมอบหมายในวงเล็บเช่นแทนif ((p=malloc(cnt))) if (p=malloc(cnt))คำเตือนเกี่ยวกับการโต้แย้งฟังก์ชั่นที่ไม่ได้ใช้สามารถระงับได้โดยคี่บางอย่างที่__attribute__ฉันจำไม่ได้หรือโดยการมอบหมายด้วยตนเอง ฯลฯ แต่โดยทั่วไปฉันชอบเพียงแค่ปิดการใช้งานตัวเลือกคำเตือนทั่วโลกที่สร้างคำเตือนสำหรับสิ่งที่จะเกิดขึ้นในรหัสที่ถูกต้อง


2
อาจจะเป็นเช่นนั้น ความตั้งใจของฉันคือไม่พิสูจน์รูปแบบกรณีทั่วไป แต่เป็นการสังเกตเกี่ยวกับปรัชญาของ gcc ว่าด้วยการยับยั้งการเตือนดูเหมือนว่าจะเป็นอย่างไร
. GitHub หยุดช่วยน้ำแข็ง

คอมไพเลอร์ทำงานแตกต่างกันด้วยคำเตือน w / r / t พร้อมวงเล็บที่เพิ่มเข้ามา?!?! ?? !!!! ว้าว! นั่นเป็นสิ่งที่ไม่คาดคิด
Jason S

1
@ JasonS parens ไม่เปลี่ยนพฤติกรรมของคำสั่ง wrt compiler สิ่งที่ทำคือเปลี่ยนซีแมนทิกส์ของ statement parens พิเศษทำให้คอมไพเลอร์เสร็จสิ้นการกำหนดและเก็บค่าสุดท้ายเป็นนิพจน์ซึ่งไม่สมควรได้รับคำเตือน หากคุณต้องการความชัดเจนคุณสามารถพูดได้if ((p=malloc(cnt)) != NULL) ...ว่าเป็นสิ่งที่คอมไพเลอร์กำลังทำอยู่เบื้องหลัง
Jesse Chisholm

@JesseChisholm: ฉันไม่คิดว่าคำอธิบายของคุณถูกต้อง
. GitHub หยุดช่วยน้ำแข็ง

3

สำหรับผู้ที่พบหน้านี้กำลังมองหาวิธีการทำสิ่งนี้ใน IAR ลองสิ่งนี้:

#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

ดูhttp://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.htmlสำหรับการอ้างอิง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.