{"id":99685,"date":"2018-09-10T07:00:00","date_gmt":"2018-09-10T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=99685"},"modified":"2019-03-13T00:29:39","modified_gmt":"2019-03-13T07:29:39","slug":"20180910-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180910-00\/?p=99685","title":{"rendered":"How can I conditionally compile based on a preprocessor macro value, while ensuring that the macro is correctly spelled?"},"content":{"rendered":"<p>Continuing on the extremely sporadic topic of <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20180628-00\/?p=99115\">stupid C preprocessor tricks<\/a>. <\/p>\n<p>It is common to have preprocessor macros that control compile-time behavior. C++11 has <code>std::enable_if<\/code> to conditionally remove functions and template specializations from consideration, and C++17 adds <code>if constexpr<\/code> to allow statements to removed conditionally. Removing variables is a bit trickier, though. You can probably manage it by wrapping the variable inside a class that itself uses <code>std::enable_if<\/code>, but that&#8217;s even more clunky than <code>std::enable_if<\/code> already is. <\/p>\n<p>Anyway, for whatever reason, you might want to use the preprocessor&#8217;s <code>#if<\/code> directive to perform your tests. Maybe you are preprocessing something for a purpose other than compilation by a C or C++ compiler. <\/p>\n<p>But you&#8217;re also worried that somebody might misspell your symbol. <\/p>\n<pre>\n\/\/ The FEATURE_BLAH macro is defined either as 0 or 1\n\n#if FEATURE_BLUH\n... do stuff with feature Blah ...\n#endif\n<\/pre>\n<p>Oops, they misspelled <code>FEATURE_<code><\/code>BLAH<\/code>, but the preprocessor doesn&#8217;t know that, so it happily says, &#8220;Nope, it&#8217;s not defined, skip the body of the <code>#if<\/code>.&#8221; <\/p>\n<p>How do you catch this typo? <\/p>\n<p>You can use your adversary&#8217;s power against him. <\/p>\n<p>Since undefined symbols are treated as having the value zero, you can use an expression that blows up if the value is zero. <\/p>\n<pre>\n\/\/ The FEATURE_BLAH macro is defined either as 1 (off) or 2 (on)\n\n#define GET_NONZERO_VALUE(x) (0\/(x) + (x))\n\n#if GET_NONZERO_VALUE(FEATURE_BLAH) == 2\n... do stuff with feature Blah ...\n#endif\n<\/pre>\n<p>The <code>GET_<code><\/code>NONZERO_<code><\/code>VALUE<\/code> macro first tries to divide by its parameter. If the parameter is not defined or is defined with the value zero, then that results in a division by zero and you get a compiler error. If the parameter is defined with a nonzero value, then the result of <code>0\/(x)<\/code> is zero, and adding that to <code>x<\/code> yields <code>x<\/code>. <\/p>\n<p>The last wrinkle is using the <code>defined<\/code> preprocessor pseudo-function to distinguish between an undefined macro and a defined macro whose value is zero. <\/p>\n<pre>\n\/\/ The FEATURE_BLAH macro is defined to 0 or 1\n\/\/ The FEATURE_BLAH_OPTION macro is some value\n\n#define GET_FEATURE_VALUE(x) (0\/defined(FEATURE_##x) + (FEATURE_##x))\n\n#if GET_FEATURE_VALUE(BLAH)\n#if GET_FEATURE_VALUE(BLAH_OPTION) == 1\n... do stuff with feature Blah and option 1...\n#elif GET_FEATURE_VALUE(BLAH_OPTION) == 2\n... do stuff with feature Blah and option 2...\n#else\n#error Unknown option for FEATURE_BLAH_OPTION.\n#endif\n#endif\n<\/pre>\n<p>If <code>FEATURE_<code><\/code>BLAH<\/code> is not defined, then the <code>defined(FEATURE_<code><\/code>BLAH)<\/code> will evaluate to zero, and then you get a divide by zero error in the preprocessor. If it is defined, then <code>defined(FEATURE_<code><\/code>BLAH)<\/code> evaluates to 1, and the expression <code>0\/1 + FEATURE_<code><\/code>BLAH<\/code> reduces to just <code>FEATURE_<code><\/code>BLAH<\/code>. <\/p>\n<p>This is an abuse of the preprocessor, but it may come in handy in a pinch. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Another stupid preprocessor trick.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-99685","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Another stupid preprocessor trick.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/99685","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=99685"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/99685\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=99685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=99685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=99685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}