英文:
Avoiding "warning C4005: 'INT8_MIN': macro redefinition" when using flex/bison in a C++ project
问题
The generated code for the lexer includes the section below:
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <inttypes.h>
typedef int8_t flex_int8_t;
// ... more typedefs here
#else
typedef signed char flex_int8_t;
// ... more typedefs here
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
// ... more defines here
#endif /* ! C99 */
Windows compilations warn you about all those integral types already being defined in stdint.h
(e.g. Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\stdint.h(49,1)
).
I understand this happens because C++ compilations don't set _STDC_VERSION__
.
I have tried setting it as a compile flag (/D___STDC_VERSION__:199901L /D__STDC_VERSION__:199901L
) but that didn't help (it would also look very dirty if it actually did work).
Is there a way to avoid those warnings? E.g. setting __STDC_VERSION__
in some other way. Or having more control over that section of flex generated code?
英文:
I have a C++ project that is using flex/bison.
The generated code for the lexer includes the section below:
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <inttypes.h>
typedef int8_t flex_int8_t;
// ... more typedefs here
#else
typedef signed char flex_int8_t;
// ... more typedefs here
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
// ... more defines here
#endif /* ! C99 */
Windows compilations warn you about all those integral types already being defined in stdint.h
(e.g. Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\include\stdint.h(49,1)
).
I understand this happens because C++ compilations don't set _STDC_VERSION__
.
I have tried setting it as a compile flag (/D___STDC_VERSION__:199901L /D__STDC_VERSION__:199901L
) but that didn't help (it would also look very dirty if it actually did work).
Is there a way to avoid those warnings? E.g. setting __STDC_VERSION__
in some other way. Or having more control over that section of flex generated code?
答案1
得分: 4
I actually ran into the same issue when working on my own Flex + Bison project.
The problem has nothing to do with the value of __STDC_VERSION__
. The warning is for macro redefinition, e.g. for INT8_MIN
, etc., which you can see when looking at the source file, e.g.
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
/* ... */
These INT8_MIN
, INT16_MIN
, etc. macros are defined in stdint.h
, so I am guessing that you are seeing this warning because your .l
file has a block enclosed with %{
and }%
in the definitions section with some #include
directives, one of which is transitively including stdint.h
.
You can easily fix this by adding the following to your .l
file's definition section:
%top{
#include <stdint.h>
}
This can be replaced with <cstdint>
if compiling the Flex output as C++.
The reason %top
is necessary is because contents enclosed in %{
and }%
, at least for Flex 2.6.4 that I am using, are copied into the generated source after the INT8_MIN
, INT16_MIN
, etc. macros get defined, so any #include
that transitively includes stdint.h
will redefine those macros, which is what MSVC is complaining about and giving you this warning for.
In contrast, the %top
block, as noted in the Flex documentation, will have its contents copied to the top of the generated source file before any Flex definitions. You need not put all your #include
directives in a top block unless, e.g. for stdint.h
, there is some particular need.
英文:
I actually ran into the same issue when working on my own Flex + Bison project.
The problem has nothing to do with the value of __STDC_VERSION__
. The warning is for macro redefinition, e.g. for INT8_MIN
, etc., which you can see when looking at the source file, e.g.
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
/* ... */
These INT8_MIN
, INT16_MIN
, etc. macros are defined in stdint.h
, so I am guessing that you are seeing this warning because your .l
file has a block enclosed with %{
and }%
in the definitions section with some #include
directives, one of which is transitively including stdint.h
.
You can easily fix this by adding the following to your .l
file's definition section:
%top{
#include <stdint.h>
}
This can be replaced with <cstdint>
if compiling the Flex output as C++.
The reason %top
is necessary is because contents enclosed in %{
and }%
, at least for Flex 2.6.4 that I am using, are copied into the generated source after the INT8_MIN
, INT16_MIN
, etc. macros get defined, so any #include
that transitively includes stdint.h
will redefine those macros, which is what MSVC is complaining about and giving you this warning for.
In contrast, the %top
block, as noted in the Flex documentation, will have its contents copied to the top of the generated source file before any Flex definitions. You need not put all your #include
directives in a top block unless, e.g. for stdint.h
, there is some particular need.
答案2
得分: 2
Here's the translated content:
查看更新内容:
你正在编译C++,而不是C。你不能假设C++编译器会定义__STDC_VERSION__
,而且自己定义它可能会误导。
<stdint.h>
和<inttypes.h>
头文件是在C99中引入的,所以在C代码中测试__STDC_VERSION__ >= 199901L
是有意义的。
这些头文件以及它们的C++等效版本<cstdint>
和<cinttypes>
是在2011年ISO C++标准中引入的(当然是从C中采用的)。在C++代码中,你应该测试__cplusplus
是否已定义,并且大于或等于201103L
。
请注意,如果你只想要类型定义和边界宏,你可能应该包含<cstdint>
。<cinttypes>
头文件包括<cstdint>
并且还定义了一些用于printf
的宏,这可能在C++中不需要。
更新:
我看到你的问题中的代码是由flex
生成的,并且正在编译为C++。根本原因是flex
中的一个bug。
flex
有一个--c++
选项,告诉它生成用于C++编译而不是C编译的代码。不幸的是,生成的C++代码仍然引用__STDC_VERSION__
宏,而这个宏可能或可能不被C++编译器定义。它应该引用__cplusplus
而不是它。
(在flex git repo中有更新,可以修复这个问题,但它们尚未出现在任何发布的版本中。最近的flex
版本,2.6.4,是从2017年发布的。)
这可能导致假阴性,即头文件无法检测到实现中有<cstdint>
,因此它会不必要地定义自己的类型,如flex_int8_t
等。
phetdam的答案可能提供了比我的更好的解决方法,但我在这里提供了一些背景信息。
英文:
See UPDATE below.
You're compiling C++, not C. You can't assume that a C++ compiler will define __STDC_VERSION__
, and it would be misleading to define it yourself.
The <stdint.h>
and <inttypes.h>
headers were introduced in C99, so testing for __STDC_VERSION__ >= 199901L
makes sense in C code.
Those headers, and their C++ equivalents <cstdint>
and <cinttypes>
, were introduced to C++ in the 2011 ISO C++ standard (adopted from C, of course). In C++ code, you should test that __cplusplus
is defined and is greater than or equal to 201103L
.
Note that if you just want the type definitions and bounds macros, you should probably include <cstdint>
. The <cinttypes>
header includes <cstdint>
and additionally defines a number of macros for use with printf
, something that you probably don't need in C++.
UPDATE:
I see that the code in your question is generated by flex
, and is being compiled as C++. The underlying cause is a bug in flex
.
flex
has a --c++
option that tells it to generate code intended to be compiled as C++ rather than as C. Unfortunately, that generated C++ code still refers to the __STDC_VERSION__
macro, which may or may not be defined by a C++ compiler. It should be referring to __cplusplus
instead.
(There are updates in the flex git repo that fix this, but they do not yet appear in any released version. The most recent flex
release, 2.6.4, is from 2017.)
The result of this is likely to be a false negative, i.e., the header doesn't detect that the implementation has <cstdint>
, so it unnecessarily defines its own types flex_int8_t
et al.
phetdam's answer likely provides a better workaround than mine, but I've tried here to provide some background information.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论