问题标签 [c-standard-library]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
0 回答
166 浏览

c - 从用户定义的函数设置 errno

据我所知,如果不是所有标准 C 函数,大多数(如果不是全部)都会将全局设置为errno失败以表示发生了什么,因此该值可用于日志记录、调试或测试。是否建议用户定义的函数使用相同的行为,或者我们应该使用一个local_errno接受具有相同含义的相同值的全局变量来模仿它?

例如,我正在编写一个计算器,并且我想要一个加法函数来报告溢出:

0 投票
1 回答
108 浏览

c - 使用标准 C 库将文件读取到内存 - Windows 过早识别 EOF 但适用于 Mac、Linux

这感觉像是最愚蠢的问题,但希望有人能提供帮助。抱歉这篇文章太长了,但我想提供足够的细节,以免人们建议我已经尝试过的东西。

我已经隔离了一个我编写的 C 程序的问题,该程序应该在 Mac、Linux 和 Windows 上发布。该程序无法在 Windows 上运行,但可以在 Mac 和 Linux 上正常运行,并且在最近的更改之前曾经在 Windows 上运行。

失败的直接原因与将文件读入内存块有关 - 所以我将代码隔离到一个自包含的程序中,并使用一些示例数据对其进行了测试,这些数据在 Windows 上可靠地失败并在 Mac 和 Linux 上正常工作。

需要注意的是,在 Windows 上,我使用的是 Visual Studio 2019(版本 16.5.5)。我正在 64 位戴尔笔记本电脑上使用 Windows 10 Enterprise 对其进行测试。在 Linux 上,我使用 gcc(我正在使用 Ubuntu 20.04 对其进行测试)。在 mac 上,我使用 clang 编译它。该程序旨在可移植(至少在这三个平台之间)。

加载文件的基本策略是使用 fopen() 打开文件,然后使用 fseek() 测量文件,将文件标记移动到文件末尾,使用 ftell() 获取文件内的位置,然后fseek() 回到开头,然后使用 ftell() 获取文件开头的位置(实际上通常为零,但不能保证),然后我从结束位置减去开始位置确定文件大小。这种“测量文件”代码在实践中似乎可以可靠地测量我关心的三个平台上的文件。

然后,我调用 malloc() 分配一块足够大的内存来保存文件。这总是很好。我使用的文件大约是 200K,它们是二进制文件——但出于隔离目的,我能够通过 271 字节的文件使其可靠地失败。原始代码只是使用了一个从 0 到文件大小的 for 循环,并重复调用 getc(fileptr),然后将每个字节分配到内存缓冲区中。然后它关闭了文件。此代码在 Mac 和 Linux 上运行良好,但在 Windows 上无法运行。我观察到的是我会得到文件的第一部分——在某些情况下是文件的大部分——然后我会开始从 getc(fileptr) 调用中读取“ff”,这将填满内存的其余部分——显然错了。

所以我研究了 getc() 和 fgetc() 之间的区别,显然 getc() 有时可能是一个不止一次评估事物的宏。这似乎不是一个明显的罪魁祸首,但我还是改成了 fgetc() 并没有改变任何东西。我还将 malloc() 调用更改为 calloc(),这样我就可以从全零开始,并且更容易使用调试器查看正在读取的文件(即查看内存缓冲区并查看它正在被写入)。

我使用 Hex 编辑器创建了一个包含以下数据的文件,以便我可以使用它进行更系统的测试。该文件包含 271 个字节。前 256 个字节是所有可能的字节值:00 01 02 03 ... fc fd fe ff。最后 16 个字节是 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f。这样,我可以查看问题是否是由尝试读取某些特定字节值引起的,并且我可以让它继续通过所有可能的字节值并以相同的模式再执行 16 个字节,只是为了更好地衡量,我可以轻松查看是否最后一个字节是 0f。

接下来我使用预处理器#if 0/#if 1 切换在使用 fgetc() 的文件读取版本和使用 fread() 的版本之间切换。这是我得到关于可能发生的事情的第一个有趣线索的地方。

在 Mac/Linux 上,该程序的两个版本都可以正确打印我期望的值。但是,在 Windows 上,fread() 版本读取前 26 个字节,之后所有字节为 00(因为 calloc 将整个块的值设置为 00,而 fread() 仅设置前 26 个字节)。文件读取的 getc() 版本正确读取前 26 个字节,然后所有后续字节为 ff。

前 26 个字节是:0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16 198 0x。

Mac 上程序的完整(正确)输出是:

szFile: 271 读取 271 字节 load_ggx_file:0 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6f 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a 0x7b 0x7c 0x7d 0x7e 0x7f 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 0xa90xaa 0xab 0xac 0xad 0xae 0xaf 0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8 0xb9 0xba 0xbb 0xbc 0xbd 0xbe 0xbf 0xc0 0xc1 0xc2 0xc3 0xc4 0xc5 0xc6 0xc7 0xc8 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 0xd0 0xd1 0xd2 0xd3 0xd4 0xd5 0xd6 0xd7 0xd8 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f0xef 0xf0 0xf1 0xf2 0xf3 0xf4 0xf4 0xf5 0xf6 0xf7 0xf7 0xf8 0xf9 0xf9 0xfa 0xfb 0xfb 0xfb 0xfc 0xfc 0xfd 0xfe 0xff 0xff 0xff 0x00 0x01 0x01 0x02 0x02 0x04 0x0504 0x05 0x06 0x06 0x00 x00 x00 x00 x00 x00 x00 x00 x000 x000 x000 x000 x000 x000 x0000 x000 x000 x000 x000 x0000 x00 0TS00B0xef 0xf0 0xf1 0xf2 0xf3 0xf4 0xf4 0xf5 0xf6 0xf7 0xf7 0xf8 0xf9 0xf9 0xfa 0xfb 0xfb 0xfb 0xfc 0xfc 0xfd 0xfe 0xff 0xff 0xff 0x00 0x01 0x01 0x02 0x02 0x04 0x0504 0x05 0x06 0x06 0x00 x00 x00 x00 x00 x00 x00 x00 x000 x000 x000 x000 x000 x000 x0000 x000 x000 x000 x000 x0000 x00 0TS00B

在 Window 上使用 fread() 版本打印:

szFile: 271 ferror: 0 feof: 1 读取 26 字节 load_ggx_file:0 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0000000 0x0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0000000 0x

在 Windows 上,当 fread 返回的值低于您要求的值时(即我的情况下的第三个参数),您应该检查 ferror() 和 feof()。我发现 ferror() 返回 0 并且 feof() 返回 1。所以问题似乎是 Windows 认为它​​已到达文件末尾。问题是它为什么会这样认为,考虑到我的限制,什么是合理的替代方案?(即我想只使用标准库编写可移植的 C 代码——而不是一堆特定于平台的代码)。

我确实检查了问题是否仅仅是由于 0x20 字符造成的。我尝试使用十六进制编辑器在我的测试文件中的 0x01 之后插入一个 0x20,发生的事情是它读取并打印了该字符只是文件的表示,并且仍然在 0x19 字符之后停止。似乎没有任何特定的角色总是导致它窒息。

这是完整的测试程序:

0 投票
1 回答
105 浏览

c - 操作数求值顺序的矛盾

当我从 deitel c 学习 C 中的递归函数时,我读到了这句话:

标准 C 没有指定大多数运算符(包括 +)的操作数的计算顺序。

但书中还说:

'+' 从左到右的结合性

操作数的求值顺序:

操作数的求值顺序

谁能解释这是为什么?

0 投票
1 回答
101 浏览

c - 为什么在库函数之前有一个序列点?

标准说:

在库函数返回之前有一个序列点。C17dr § 7.1.4 3。

我知道在实际调用之前和 return 语句之后有一个序列点(由于分号,如果有其他原因请告诉我)但我无法理解上面的句子。谁能解释一下?

0 投票
2 回答
157 浏览

c - 我可以禁用或忽略 Apple 对 C 标准头文件的添加吗?

我正在开发一个 C 应用程序,我希望它具有合理的可移植性。它可以在 Linux 上使用 gcc 和 clang 以及在 Windows 上使用 MSVC 构建。访问 Mac 后,我尝试使用命令行工具进行构建。

它无法编译,因为我的代码声明了一个函数isnumber,而 Apple 的ctype.h标头也声明了一个 (non standard?) isnumber。我可以重命名我的函数,这样它就不会发生冲突,但是有没有办法通过禁用或忽略所有或特定的 Apple 对标准头文件的添加来避免这种情况?例如,是否有编译器选项或预处理器编译指示可以忽略它们?

isnumber无法检查字符类。下面是重现该问题的代码 - 它使用 clang/Linux 和 MSVC/Windows 编译,但不在 Mac 上编译( - 它不是实际代码)。

错误:

更新:

正如 Acorn 的回答和评论所描述的那样,“isnumber”是C11标准保留的函数的错误名称:

7.31 未来的图书馆方向
为了方便起见,以下名称被分组在单独的标题下。 无论程序包含什么标头,下面描述的所有外部名称都是保留的。

...

7.31.2 字符处理<ctype.h>“以or
开头的函数名和一个小写字母可以添加到标题中的声明中”。isto<ctype.h>

所以我原来的问题的“正确”解决方案是重命名我的函数。

0 投票
1 回答
433 浏览

cmake - 未定义的符号仍然存在,但共享库可以编译并且似乎可以正常运行

我的目标是从SUNDIALS 2.7.0构建共享库- 这些是用 C 编写的常微分方程的求解器。

我已经下载了源代码,并按照安装指南进行操作:

  1. 运行 Cmake(带 GUI),检查选项“CVODE” (这是可用的求解器之一 - 我想要的唯一一个),“构建共享库”和“使用通用(std-c)数学库”并生成 Makefile。
  2. 在 Linux 控制台中运行make && make install并生成我的共享库,完全没有错误消息。这是输出:

这些共享库似乎在我的项目中正常运行,为此我需要它们 - 常微分方程正在得到求解,并且输出似乎与独立于这些的其他求解器相同。

但是有一个很大的但是:):检查生成的共享库中的未定义符号向我展示了标准函数的简短列表 - 这是共享库的输出:

打印共享库依赖项给出:

例如,像SUNRsqrt这样的函数是在sqrt上定义的,并且在实际数值计算中非常重要——这一事实以及未定义符号的存在让我感到困惑和担心共享库的可靠性。

在生成共享库之前,我已经为环境变量 LD_LIBRARY_PATH 设置了所有适当的路径(顺便说一下,它之前是空的):

例如,C 标准库libc.so和 C 数学库libm.so存储在/usr/lib/x86_64-linux-gnu,而 GNU 事务内存库libitim.so存储在/usr/lib/gcc /x86_64-linux-gnu(虽然它的 1.0.0 版本也在/usr/lib/x86_64-linux-gnu)。

操作系统、Cmake、GNU C 编译器和 GNU Make 的版本:

任何评论将不胜感激。

PS 这个案例是完全可重现的,因为它是关于从 SUNDIALS 2.7.0 源(直接下载链接)生成共享库并在未定义的符号上检查它们。

0 投票
0 回答
68 浏览

c - 静态链接的 C 程序中将包含哪些库?

我有以下程序:

我编译它(动态链接)并ldda.out. 我看见:

  • 第一个是内核提供的虚拟共享对象。
  • 第二个是C标准库。
  • 第三个是动态链接器。

我不确定第一个和第三个如何受到静态链接的影响,我想知道是否使用了整个标准库,即使我只包含一个标头。

如果我静态链接这个程序,生成的二进制文件会

  • 包含linux-vdso.so.1,即使它是由内核提供的?
  • 包含整个 C 标准库,即使我只包含<stdio.h>?
  • 包含ld-linux-x86-64.so.2,即使它用于运行动态链接的程序?
0 投票
1 回答
48 浏览

c - C99 嵌套数组未定义行为

在我们的讲座中,我们最近查看了关于指针相等的 c99 标准(6.5.9.6)并将其应用于嵌套数组。那里指出,只有在“一个是指向一个超过一个数组对象末尾的指针,另一个是指向另一个数组对象的开头的指针,该数组对象恰好紧跟在第一个数组对象之后,才能保证指针相等。地址空间”。

教授随后解释说,这就是数组访问 a[0][19] 在技术上对于尺寸为 4*5 的嵌套数组未定义的原因。这是真的?如果是这样,为什么要定义负索引,例如 a[1][-1]?

0 投票
0 回答
69 浏览

c - 在C中的坐标处打印字符

我想用 C 为 Linux 编写一个类似于 vi 的文本编辑器(只是作为个人练习),我意识到如果我可以在 C 中的精确位置打印一个字符,那将非常有用。是否有标准中的函数完成这个的图书馆?就像是:

0 投票
1 回答
154 浏览

c - C 标准库中的任何函数是否隐式使用`stderr`?

C 规范要求所有 C 程序都有 3 个开放的流可供它们使用:stdoutstdinstderr.

用户可以根据需要使用这些流,例如:

C 标准库中的一些函数隐式使用这些函数,例如:

  1. C 标准库中的任何函数是否隐式使用stderr
  2. C 标准库的常见实现中的任何stderr函数(例如 Linux 上的 GNU 的 glibc)是否隐式使用?