有没有办法包含 stdio.h 但忽略其中的某些功能?
Is there a way to include stdio.h but ignore some of the functions therein?
让我先声明这个问题,我几乎是一个编程新手,并且在 C 或 GNU 环境中都没有受过良好的训练。另外,我真的无法提供可重现的示例,因为我还没有编写这段代码,我只是在尝试构建它。我已经自学了足够的东西来编译一些程序,给出了一个很好的预先存在的 makefile,并且多次使用 Rtools 为 Windows 编译了 R。
我一直在尝试使用 GCC 4.8.4 为 Windows(7 64 位)编译 R(Rtools 仍然存在于 4.6.3 预发布版中,并且 4.9 中的链接时优化已经复活 some old bugs), and can do so with one problem. In one of the files (/src/extra/trio/compat.c 准确地说)既包含 stdio.h 又包含 sprintf
和 vsprintf
的定义。因此,构建崩溃并出现以下错误:
In file included from compat.c:3:0:
F:/MinGW64/x86_64-w64-mingw32/include/stdio.h:553:5: note: previous
definition of 'snprintf' was here
int snprintf (char * __restrict__ __stream, size_t __n, const char *
__restrict__ __format, ...)
^
compat.c:75:5: error: redefinition of 'vsnprintf'
int vsnprintf(char *buffer, size_t bufferSize, const char *format,
va_list args)
^
In file included from compat.c:3:0:
F:/MinGW64/x86_64-w64-mingw32/include/stdio.h:543:7: note: previous
definition of 'vsnprintf' was here
int vsnprintf (char * __restrict__ __stream, size_t __n, const char
* __restrict__ __format, va_list __local_argv)
^
../../gnuwin32/MkRules:218: recipe for target 'compat.o' failed
make[4]: *** [compat.o] Error 1
Makefile:120: recipe for target 'rlibs' failed
make[3]: *** [rlibs] Error 1
Makefile:179: recipe for target '../../bin/x64/R.dll' failed
make[2]: *** [../../bin/x64/R.dll] Error 2
Makefile:104: recipe for target 'rbuild' failed
make[1]: *** [rbuild] Error 2
Makefile:14: recipe for target 'all' failed
make: *** [all] Error 2
compat.c中的行是65-79中的行:
int snprintf(char *buffer, size_t max, const char *format, ...)
{
int res;
va_list(ap);
va_start(ap, format);
res = trio_vsnprintf(buffer, max, format, ap);
va_end(ap);
return res;
}
int vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
{
return trio_vsnprintf(buffer, bufferSize, format, args);
}
如果我删除这些行,构建完成,但 R 输出有一个三位十进制科学记数法指数而不是两位数,(例如“3.11e-004”而不是“3.11e-04”)这会导致各种检查崩溃。 I have been informed 这是标准的 Windows 方法,所以我删除本地 R 版本几乎肯定会导致这个问题。
我的问题是,有什么方法可以继续将 stdio.h 包含在 compat.c 文件中,同时将 snpritf
和 vsnprintf
重新定义为compat.c?
中的本地
谢谢。
尝试 1 失败
我尝试添加直接 #undef
声明以及
#ifdef snprintf
#undef snprintf
#endif
和 compat.c 中对应的 vsnprintf
,但均无效。由于“重新定义”,我遇到相同的构建错误而崩溃。
尝试 2 失败
将 compat.c 中的代码更改为:
#ifdef snprintf
#undef snprintf
int snprintf(char *buffer, size_t max, const char *format, ...)
{
int res;
va_list(ap);
va_start(ap, format);
res = trio_vsnprintf(buffer, max, format, ap);
va_end(ap);
return res;
}
#endif
允许程序编译,但它有相同的符号错误,这意味着它在功能上等同于只删除这些行。
根据评论请求更新
- 安装 Mingw-64 的一些风格并将 \bin 放在 PATH 的开头
- 安装 MSYS2:基本安装,然后添加 tar、make、zlib、zip、unzip 和 rsync,并将其 bin 放在路径的第二个
- Untar R-3.1.2.tar.gz(两次,作为第一次 returns 使用来自 MSYS2 的 tar 1.28 的 simlink 错误。使用修补的 tar 来自 Rtolls 的 1.2.1 没有 return 错误)
- 将 R64 (Rtools) 中的 Tcl 和 bitmapdll 子目录复制到适当的位置
- 修改MkRules.dist强制执行64位,Windows64平台,HTML帮助,以及Cairo、Inno和qpdf的正确目录,并将其另存为MkRules.local.对于这些测试,我没有使用基于 OpenBLAS 的 Rblas,除了为速度
添加 -pipe
之外,没有任何特定于处理器的 EOPTS 调用
- 运行
make all
我已经使用 Rtools 中的二进制文件多次构建 R,包括使用 OpenBLAS(愚弄 R 以为它是 ATLAS)。我注意到但不明白的是 stdio.h
在 GCC 4.7(因此是 4.6)和 4.8 及后续版本之间发生了变化。包含错误中抛出的行号的新版本直接定义了 snprintf
和 vsnprintf
。 4.6.3 的版本没有。我复制了以下部分:
stdio.h 来自 GCC 4.6.3 第 494–514 行:
#if !defined (__USE_MINGW_ANSI_STDIO) || __USE_MINGW_ANSI_STDIO == 0
/* this is here to deal with software defining
* vsnprintf as _vsnprintf, eg. libxml2. */
#pragma push_macro("snprintf")
#pragma push_macro("vsnprintf")
# undef snprintf
# undef vsnprintf
int __cdecl vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
__MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
#ifndef __NO_ISOCEXT
int __cdecl snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __CRT__NO_INLINE
__CRT_INLINE int __cdecl vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
{
return _vsnprintf (d, n, format, arg);
}
#endif /* !__CRT__NO_INLINE */
#endif /* !__NO_ISOCEXT */
#pragma pop_macro ("vsnprintf")
#pragma pop_macro ("snprintf")
#endif
stdio.h 来自 GCC 4.9.2(与 4.8.4 相同)第 531–565 行:
#if !defined (__USE_MINGW_ANSI_STDIO) || __USE_MINGW_ANSI_STDIO == 0
/* this is here to deal with software defining
* vsnprintf as _vsnprintf, eg. libxml2. */
#pragma push_macro("snprintf")
#pragma push_macro("vsnprintf")
# undef snprintf
# undef vsnprintf
int __cdecl __ms_vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
__MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
{
return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}
int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __NO_ISOCEXT
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
__builtin_va_end( __local_argv );
return __retval;
}
#endif /* !__NO_ISOCEXT */
#pragma pop_macro ("vsnprintf")
#pragma pop_macro ("snprintf")
#endif
正如您所观察到的,compat.c
中引入的 MinGW GCC 4.7 中的编译错误是由于
通过在 stdio.h
中新包含 vsprintf
和 snprintf
(以及其他)的内联定义。
这打破了之前的代码,比如 compat.c
拒绝了标准库的
以前是外部定义并提供自己的定义。
您可以根据问题函数恢复原状,这取决于预处理器的定义
宏,即只有适当定义宏的客户端代码才能在 状态下编译该函数
从前;其他代码将在现状.
下编译它
要做到这一点,您必须对问题进行一些预处理 header F:/MinGW64/x86_64-w64-mingw32/include/stdio.h
.
替换[541-560]行,即:
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
{
return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}
int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __NO_ISOCEXT
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
__builtin_va_end( __local_argv );
return __retval;
}
与:
#if NO_INLINE_VSNPRINTF == 0
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
{
return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}
#else
extern int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv);
#endif`
int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __NO_ISOCEXT
#if NO_INLINE_SNPRINTF == 0
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
__builtin_va_end( __local_argv );
return __retval;
}
#else
extern int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...);
#endif
(注意保留 #endif
,最初在第 561 行,紧跟在结束此 hack 的那个之后。)
然后,编辑 compat.c
并在顶部右侧 before:
#include <stdio.h>
添加行:
#define NO_INLINE_VSNPRINTF 1
#define NO_INLINE_SNPRINTF 1
(这两个宏没有约定俗成的意思,我自己造的。)
保存这些更改后,compat.c
将无错误地编译。至少对我来说是这样。
我还没有解决 R 的完整 Windows 构建的问题,因此您可能会遇到更多问题
破损。如果有同类的话,解法是这样的:如果一个header
#include
由 foo.c
编辑的文件 header.h
提供了一个内联函数定义
形式:
__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
....
}
然后在 header.h
中将其替换为:
#if NO_INLINE_FUNC_NAME == 0
__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
....
}
#else
extern some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...]);
#endif
并在 foo.c
中,就在 #include <header.h>
之前插入:
#define NO_INLINE_FUNC_NAME 1
让我先声明这个问题,我几乎是一个编程新手,并且在 C 或 GNU 环境中都没有受过良好的训练。另外,我真的无法提供可重现的示例,因为我还没有编写这段代码,我只是在尝试构建它。我已经自学了足够的东西来编译一些程序,给出了一个很好的预先存在的 makefile,并且多次使用 Rtools 为 Windows 编译了 R。
我一直在尝试使用 GCC 4.8.4 为 Windows(7 64 位)编译 R(Rtools 仍然存在于 4.6.3 预发布版中,并且 4.9 中的链接时优化已经复活 some old bugs), and can do so with one problem. In one of the files (/src/extra/trio/compat.c 准确地说)既包含 stdio.h 又包含 sprintf
和 vsprintf
的定义。因此,构建崩溃并出现以下错误:
In file included from compat.c:3:0:
F:/MinGW64/x86_64-w64-mingw32/include/stdio.h:553:5: note: previous
definition of 'snprintf' was here
int snprintf (char * __restrict__ __stream, size_t __n, const char *
__restrict__ __format, ...)
^
compat.c:75:5: error: redefinition of 'vsnprintf'
int vsnprintf(char *buffer, size_t bufferSize, const char *format,
va_list args)
^
In file included from compat.c:3:0:
F:/MinGW64/x86_64-w64-mingw32/include/stdio.h:543:7: note: previous
definition of 'vsnprintf' was here
int vsnprintf (char * __restrict__ __stream, size_t __n, const char
* __restrict__ __format, va_list __local_argv)
^
../../gnuwin32/MkRules:218: recipe for target 'compat.o' failed
make[4]: *** [compat.o] Error 1
Makefile:120: recipe for target 'rlibs' failed
make[3]: *** [rlibs] Error 1
Makefile:179: recipe for target '../../bin/x64/R.dll' failed
make[2]: *** [../../bin/x64/R.dll] Error 2
Makefile:104: recipe for target 'rbuild' failed
make[1]: *** [rbuild] Error 2
Makefile:14: recipe for target 'all' failed
make: *** [all] Error 2
compat.c中的行是65-79中的行:
int snprintf(char *buffer, size_t max, const char *format, ...)
{
int res;
va_list(ap);
va_start(ap, format);
res = trio_vsnprintf(buffer, max, format, ap);
va_end(ap);
return res;
}
int vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
{
return trio_vsnprintf(buffer, bufferSize, format, args);
}
如果我删除这些行,构建完成,但 R 输出有一个三位十进制科学记数法指数而不是两位数,(例如“3.11e-004”而不是“3.11e-04”)这会导致各种检查崩溃。 I have been informed 这是标准的 Windows 方法,所以我删除本地 R 版本几乎肯定会导致这个问题。
我的问题是,有什么方法可以继续将 stdio.h 包含在 compat.c 文件中,同时将 snpritf
和 vsnprintf
重新定义为compat.c?
谢谢。
尝试 1 失败
我尝试添加直接 #undef
声明以及
#ifdef snprintf
#undef snprintf
#endif
和 compat.c 中对应的 vsnprintf
,但均无效。由于“重新定义”,我遇到相同的构建错误而崩溃。
尝试 2 失败
将 compat.c 中的代码更改为:
#ifdef snprintf
#undef snprintf
int snprintf(char *buffer, size_t max, const char *format, ...)
{
int res;
va_list(ap);
va_start(ap, format);
res = trio_vsnprintf(buffer, max, format, ap);
va_end(ap);
return res;
}
#endif
允许程序编译,但它有相同的符号错误,这意味着它在功能上等同于只删除这些行。
根据评论请求更新
- 安装 Mingw-64 的一些风格并将 \bin 放在 PATH 的开头
- 安装 MSYS2:基本安装,然后添加 tar、make、zlib、zip、unzip 和 rsync,并将其 bin 放在路径的第二个
- Untar R-3.1.2.tar.gz(两次,作为第一次 returns 使用来自 MSYS2 的 tar 1.28 的 simlink 错误。使用修补的 tar 来自 Rtolls 的 1.2.1 没有 return 错误)
- 将 R64 (Rtools) 中的 Tcl 和 bitmapdll 子目录复制到适当的位置
- 修改MkRules.dist强制执行64位,Windows64平台,HTML帮助,以及Cairo、Inno和qpdf的正确目录,并将其另存为MkRules.local.对于这些测试,我没有使用基于 OpenBLAS 的 Rblas,除了为速度 添加
- 运行
make all
-pipe
之外,没有任何特定于处理器的 EOPTS 调用
我已经使用 Rtools 中的二进制文件多次构建 R,包括使用 OpenBLAS(愚弄 R 以为它是 ATLAS)。我注意到但不明白的是 stdio.h
在 GCC 4.7(因此是 4.6)和 4.8 及后续版本之间发生了变化。包含错误中抛出的行号的新版本直接定义了 snprintf
和 vsnprintf
。 4.6.3 的版本没有。我复制了以下部分:
stdio.h 来自 GCC 4.6.3 第 494–514 行:
#if !defined (__USE_MINGW_ANSI_STDIO) || __USE_MINGW_ANSI_STDIO == 0
/* this is here to deal with software defining
* vsnprintf as _vsnprintf, eg. libxml2. */
#pragma push_macro("snprintf")
#pragma push_macro("vsnprintf")
# undef snprintf
# undef vsnprintf
int __cdecl vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
__MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
#ifndef __NO_ISOCEXT
int __cdecl snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __CRT__NO_INLINE
__CRT_INLINE int __cdecl vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
{
return _vsnprintf (d, n, format, arg);
}
#endif /* !__CRT__NO_INLINE */
#endif /* !__NO_ISOCEXT */
#pragma pop_macro ("vsnprintf")
#pragma pop_macro ("snprintf")
#endif
stdio.h 来自 GCC 4.9.2(与 4.8.4 相同)第 531–565 行:
#if !defined (__USE_MINGW_ANSI_STDIO) || __USE_MINGW_ANSI_STDIO == 0
/* this is here to deal with software defining
* vsnprintf as _vsnprintf, eg. libxml2. */
#pragma push_macro("snprintf")
#pragma push_macro("vsnprintf")
# undef snprintf
# undef vsnprintf
int __cdecl __ms_vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
__MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
{
return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}
int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __NO_ISOCEXT
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
__builtin_va_end( __local_argv );
return __retval;
}
#endif /* !__NO_ISOCEXT */
#pragma pop_macro ("vsnprintf")
#pragma pop_macro ("snprintf")
#endif
正如您所观察到的,compat.c
中引入的 MinGW GCC 4.7 中的编译错误是由于
通过在 stdio.h
中新包含 vsprintf
和 snprintf
(以及其他)的内联定义。
这打破了之前的代码,比如 compat.c
拒绝了标准库的
以前是外部定义并提供自己的定义。
您可以根据问题函数恢复原状,这取决于预处理器的定义 宏,即只有适当定义宏的客户端代码才能在 状态下编译该函数 从前;其他代码将在现状.
下编译它要做到这一点,您必须对问题进行一些预处理 header F:/MinGW64/x86_64-w64-mingw32/include/stdio.h
.
替换[541-560]行,即:
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
{
return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}
int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __NO_ISOCEXT
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
__builtin_va_end( __local_argv );
return __retval;
}
与:
#if NO_INLINE_VSNPRINTF == 0
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
{
return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}
#else
extern int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv);
#endif`
int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__ format, ...);
#ifndef __NO_ISOCEXT
#if NO_INLINE_SNPRINTF == 0
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
__builtin_va_end( __local_argv );
return __retval;
}
#else
extern int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...);
#endif
(注意保留 #endif
,最初在第 561 行,紧跟在结束此 hack 的那个之后。)
然后,编辑 compat.c
并在顶部右侧 before:
#include <stdio.h>
添加行:
#define NO_INLINE_VSNPRINTF 1
#define NO_INLINE_SNPRINTF 1
(这两个宏没有约定俗成的意思,我自己造的。)
保存这些更改后,compat.c
将无错误地编译。至少对我来说是这样。
我还没有解决 R 的完整 Windows 构建的问题,因此您可能会遇到更多问题
破损。如果有同类的话,解法是这样的:如果一个header
#include
由 foo.c
编辑的文件 header.h
提供了一个内联函数定义
形式:
__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
....
}
然后在 header.h
中将其替换为:
#if NO_INLINE_FUNC_NAME == 0
__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
....
}
#else
extern some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...]);
#endif
并在 foo.c
中,就在 #include <header.h>
之前插入:
#define NO_INLINE_FUNC_NAME 1