【问题标题】:Microsoft C Run Time function implementation - now and beforeMicrosoft C 运行时函数实现 - 现在和以前
【发布时间】:2015-12-07 12:14:31
【问题描述】:

我正在尝试编写一些可移植的代码,我一直在思考 Microsoft 如何实现旧的 C 运行时例程,如 gmtimefopen 等返回指针,与今天的 gmtime_sfopen_s 相反,后者需要传递对象并返回一些 errno 状态代码(我猜)。

一种方法是在此类例程中创建静态(优于全局)对象并返回指向它的指针,但如果一个对象当前正在使用此静态指针而另一个对象调用该例程,则第一个对象将获得更改的缓冲区 - 这不好。

此外,我怀疑此类例程是否使用动态内存,因为这会导致内存泄漏。

与其他微软的东西一样,实施没有开放,所以我可以达到顶峰。有什么建议吗?

【问题讨论】:

  • 为什么需要静态对象?为什么动态内存会导致内存泄漏?
  • 如果我没记错的话,MS C 运行时源代码的大部分是随 Visual Studio 分发的。
  • 另外,对于某些库来说,在第一次调用时动态分配内存并在程序的整个生命周期中使用它并不少见。除非它添加一个 atexit 处理程序来释放内存,否则从技术上讲它是一个泄漏,但这不是一个持续的泄漏,大多数现代操作系统无论如何都会在终止时释放该内存。

标签: c runtime msdn


【解决方案1】:

首先,由于线程安全,这样的全局变量和静态变量无论如何都不能使用。

如果程序员滥用它们,动态内存、数组、句柄数组或其他此类组合的使用确实会泄漏资源。在非平凡的操作系统上,这些资源与进程相关联并在进程终止时释放,因此对于应用程序来说这是一个严重的问题,但对于操作系统来说却不是。

【讨论】:

  • 您可以在 C11 中使用线程本地存储,并且一些早期的编译器也支持它。
  • @StephenG 你是什么意思。你能解释一下这个想法吗?
  • 当您将变量声明为线程本地时,编译器将生成代码,以确保每个线程都将在其自己的变量版本上运行。魔术发生在幕后。这可能会有所帮助 [stackoverflow.com/questions/5450694/….
【解决方案2】:

关于gmtime,你是对的;它可以对具有static 存储持续时间的变量进行操作(这与声明为“全局”的变量的存储持续时间相同,顺便说一句……C 中没有“全局”)。从历史上看,您可能应该假设是这种情况,因为 C 不要求对多线程有任何支持。如果您指的是一个对多线程有良好支持的时代,那么gmtime 可能会返回具有线程特定存储持续时间的东西,而不是the MSDN documentation for gmtime 所说的gmtime 和其他类似的函数“......每个线程都使用一个通用的 tm 结构进行转换。”

但是,fopen 是一个创建资源的函数,因此可以合理地预期每个返回值都是唯一的(除非它是错误的返回值)。

的确,fopen确实构成了动态管理;完成后,您应该致电fclose 关闭FILE...如果您忘记关闭文件时不时,无需惊慌,因为 C 标准要求程序关闭所有在程序终止时仍然打开的FILEs。这意味着该程序会在幕后跟踪您的所有FILEs。

但是,在很长一段时间内一遍又一遍地反复泄露文件描述符显然是一种不好的做法。

【讨论】:

  • 智能指针的使用情况如何?我们可以实现这样的例程,可以将智能指针用于结果对象。系统应该在使用后销毁这些内存,我们仍然会有返回指针的例程。在处理这个智能指针时,我只是不知道(潜在的)系统开销。
  • @MilošLjumović 在一个与 C++ 无关的问题中,您指的是 C++ 的“智能指针”吗?
  • 不介意,但是可以。正如我所说,我正在考虑正确的方法。问题与 C 运行时有关,以便我理解其背后的概念。
  • @MilošLjumović 运行时可以检测任何类型的内存泄漏并在它们之后进行清理。 Javascript、C# 和 Java 等编程语言中的垃圾收集证明了这一点。当然,C 实现可以在 GC 之上实现 malloc(或 gmtime),并使用 free(没有对应于 gmtime 的析构函数)作为 GC 的提示......问题是实际上没有受益(由于 valgrind 等项目允许我们检测内存泄漏)(相当极端的)开销。
  • @MilošLjumović 事实上,静态检测内存泄漏是可能的……不过,您可能不想使用执行如此繁重分析的编译器……
【解决方案3】:

我不确定 Visual Studio 的细节,但这些函数库通常实现为 不透明类型。这就是为什么它们返回一个指针以及为什么你不知道FILE 结构的内容。

这意味着要么有一个静态内存池,要么在函数内部调用 malloc。不保证 C 库函数是可重入的。

在没有相应的fclose 的情况下调用fopen 可能确实会造成内存泄漏:无论如何,您都会遇到“资源泄漏”。因此,请确保您始终拨打fclose

关于实现细节:你不能有Visual Studio源代码,但你可以下载

【讨论】:

    猜你喜欢
    • 2013-02-07
    • 2021-08-04
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多