我使用的代码库历史上曾经有意地试图避免依赖于stdio.h爬行.它有自己的打印格式和机制,那些应该用来代替printf等.
但是有人经常会添加一个依赖项,必须引起注意并被删除.所以我试着为最简单的情况发出警报:
#if !defined(NDEBUG)
void printf(float dont_link_with_stdio_h);
#endif
Run Code Online (Sandbox Code Playgroud)
gcc人员似乎一直在思考如何阻止容易出错,因为如果你这样做有一个有用的信息......无论你是否包括在内<stdio.h>.
内置函数'printf'的冲突类型
有一种方法可以关闭此警告(-fno-builtin).并且有各种各样的方法可以做一些事情,例如过滤掉你不想去的东西的符号转储......
但有没有一个简单的非警告(如果你没有包括stdio.h)的方式提醒某人他们已经引入了不需要的printf用法?
这看起来像一个简单的问题,但我在这里找不到类似的东西.
由于C中没有文件复制功能,我们必须自己实现文件复制,但我不喜欢重新发明轮子,即使是那样的琐碎事情,所以我想问云:
此代码应该是可移植(在Windows/MAC/LINUX/BSD/QNX/younameit),稳定的,经过时间考验的,速度快,内存使用效率等进入特定系统的内部挤出一些性能是值得欢迎的(就像得到文件系统的簇大小) .
这似乎是一个微不足道的问题,但是,例如,CP命令的源代码不是10行C代码.
我一直在尝试打开文件和输出文本,但我一直在收到错误.所以我想我会从一开始就尝试打开文件.这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#define CORRECT_PARAMETERS 3
int main(void)
{
FILE *file;
file = fopen("TestFile1.txt", "r");
if (file == NULL) {
printf("Error");
}
fclose(file);
}
Run Code Online (Sandbox Code Playgroud)
当我运行该文件时,"错误"被打印到控制台,就是这样.TestFile1.txt与我的.exe位于同一位置.我该如何解决?
我已经制作了一个简单的资源包装器,用于将我的游戏资源打包到一个文件中.在我开始编写解包器之前,一切都很顺利.我注意到我已经打包的.txt文件--26个字节 - 来自资源文件,没有任何问题,保留了所有数据.但是,当读取我在资源文件中打包的.PNG文件时,前5个字节完好无损,而其余的则完全无效.
我追溯到打包过程,我注意到fread只读取.PNG文件的前5个字节,我不能为我的生活找出原因.它甚至触发'EOF'表示文件只有5个字节长,而实际上它是一个787字节的小多边形PNG,100px×100px.
我甚至通过单独的应用程序来简单地将这个PNG文件读入缓冲区来测试这个问题,我得到相同的结果,只读取5个字节.
以下是该小型独立应用程序的代码:
#include <cstdio>
int main(int argc, char** argv)
{
char buffer[1024] = { 0 };
FILE* f = fopen("test.png", "r");
fread(buffer, 1, sizeof(buffer), f);
fclose(f); //<- I use a breakpoint here to verify the buffer contents
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有人可以指出我的愚蠢错误吗?
在32位系统上,ftell如果以二进制模式打开的文件的当前位置指示符超过2GB点,会返回什么?在C99标准中,这是未定义的行为,因为ftell必须返回一个long int(最大值为2**31-1)?
我正在编写一个库,并希望使它绝对与资源无关,这也意味着库应该使用用户提供的内存分配功能.库允许用户也设置自己的错误处理函数,这些函数以错误消息作为参数调用,如下所示:
typedef void (*error_handler)(const char* msg);
Run Code Online (Sandbox Code Playgroud)
库代码自己准备错误消息,就像那样(消息格式化失败的情况):
char buf[BUF_SIZE];
snprintf(buf, BUF_SIZE, "Oops found at file '%s' line %d", __FILE__, __LINE__);
Run Code Online (Sandbox Code Playgroud)
但是我可以确定snprintf不会为malloc的内部使用分配更多内存,显然会绕过用户提供的分配例程吗?我的Linux系统中的手册页对此保持沉默.
我无法找到任何对使用fputc()时创建流的指定行为的引用fopen("/some/path", "r").
我搜索了C11草案n1570 pdf寻找没有运气的任何参考,fopen()功能规范谈到将未知字符作为模式参数传递,这是未定义的行为.但它没有说明创建的流上的后续IO.
这是fwrite()功能规范
7.21.8.2
fwrite功能概要
Run Code Online (Sandbox Code Playgroud)#include <stdio.h> size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);描述
- 的
fwrite函数写入,从阵列所指向的ptr,最多nmemb,其大小由指定的元素size,到流指向stream.对于每个对象,对fputc函数进行大小调用,从unsigned char完全覆盖对象的数组中获取值(按顺序).流的文件位置指示符(如果已定义)按成功写入的字符数提前.如果发生错误,则流的文件位置指示符的结果值是不确定的.返回
- 该
fwrite函数返回成功写入的元素数,这将少于nmemb仅在遇到写入错误时.如果为size或nmemb为零,则fwrite返回零,并且流的状态保持不变.
这需要我们的fputc()功能,所以
7.21.7.3
fputc功能概要
Run Code Online (Sandbox Code Playgroud)#include <stdio.h> int fputc(int c, FILE *stream);描述
- 该
fputc …
我需要开发一个C++例程来执行这个显然是微不足道的任务:只有在文件不存在时才创建文件,否则什么也不做/引发错误.
由于我需要避免竞争条件,我想使用"请求宽恕不允许"原则(即尝试预期的操作并检查它是否成功,而不是提前检查前提条件),据我所知,这是唯一的用于此目的的强大且可移植的方法[维基百科文章] [getline的一个例子].
不过,在我的案例中,我无法找到实现它的方法.我能想到的最好的是打开一个fstreamin app模式(或者fopen用"a"),用tellp(C++)或ftell(C)检查输出位置,如果这个位置不为零,则中止.然而,这有两个缺点,即如果文件存在则它被锁定(尽管很短的时间)并且其修改日期被改变.
我检查的其他可能的组合ios_base::openmode的fstream,还有mode的字符串fopen,但没有发现这适合我的需求选择.进一步搜索C和C++标准库以及Boost Filesystem,证明是无用的.
有人能否指出一种方法以一种强有力的方式执行我的任务(没有附带效应,没有竞争条件)而不依赖于OS特定的功能?我的具体问题是在Windows中,但便携式解决方案将是首选.
编辑:BitWhistler的答案完全解决了C程序的问题.不过,我很惊讶没有C++惯用解决方案似乎存在.任何一个使用Andrew Henle提出open的O_EXCL属性,但是特定于操作系统(在Windows中,属性似乎_O_EXCL用另外的下划线[MSDN]调用)或者单独编译C11文件并将其从C++代码链接.此外,获得的文件描述符不能转换为流,除非使用非标准扩展(例如GCC __gnu_cxx::stdio_filebuf).我希望未来的C++版本能够实现子"x"属性,也可能ios::实现文件流的相应修改器.
当然,磁盘上的文件缓冲I/O比无缓冲的速度快.但是为什么即使写入内存缓冲区也有好处?
以下基准代码示例使用gcc 5.40编译,使用优化选项-O3,与glibc 2.24链接.(请注意,常见的glibc 2.23有关于fmemopen()的错误.)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
int main() {
size_t bufsz=65536;
char buf[bufsz];
FILE *f;
int r;
f=fmemopen(buf,bufsz,"w");
assert(f!=NULL);
// setbuf(f,NULL); // UNCOMMENT TO GET THE UNBUFFERED VERSION
for(int j=0; j<1024; ++j) {
for(uint32_t i=0; i<bufsz/sizeof(i); ++i) {
r=fwrite(&i,sizeof(i),1,f);
assert(r==1);
}
rewind(f);
}
r=fclose(f);
assert(r==0);
}
Run Code Online (Sandbox Code Playgroud)
缓冲版本的结果:
$ gcc -O3 -I glibc-2.24/include/ -L glibc-2.24/lib test-buffered.c
$ time LD_LIBRARY_PATH=glibc-2.24/lib ./a.out
real 0m1.137s
user 0m1.132s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)
无缓冲版本的结果
$ gcc -O3 -I glibc-2.24/include/ -L glibc-2.24/lib …Run Code Online (Sandbox Code Playgroud) Docker 映像大小通常应尽可能小。使用像标准 python映像这样的成熟环境,在安装了所有依赖项的情况下,经常会导致严重臃肿的映像。将 python 打包成独立的可执行文件(例如使用 pyinstaller)是减少图像大小和整体复杂性的完美方式。
环境:python3.6,pyinstaller==3.4
出现的问题是,python 使用每个默认的缓冲 stdio。这可以通过使用python -u .... 但是在使用 pyinstaller 时变得无法访问。
根据文档,应该可以向生成的可执行文件添加运行时选项,例如u,v和W ...。但不幸的是,实际上它似乎不起作用。两者,v并且W,正常工作,但u似乎被完全忽略。
以下代码段显示了用法:
...
exe = EXE(...
[('u', None, 'OPTION')],
name="myapp",
...)
...
Run Code Online (Sandbox Code Playgroud)
这个标志还有效吗?由于其他人工作 - 它是否在没有通知或更新文档的情况下被删除?
是否有替代方法可以禁用 stdio 缓冲(使用 pyinstaller 或外部),而不像这样修改 python 代码?
在运行 docker swarm 服务时,应避免缓冲 IO。为了使可执行文件正确地实时登录到 docker 守护进程,有必要附加一个 shell。但是将 tty shell 附加到 swarm 任务会使处理日志变得更加复杂,甚至是不可能的。