【问题标题】:Is it a common practice to re-use the same buffer name for various things in C?在 C 中为各种事物重用相同的缓冲区名称是一种常见的做法吗?
【发布时间】:2010-08-15 20:32:33
【问题描述】:

例如,假设我有一个名为char journal_name[25] 的缓冲区,用于存储日志名称。现在假设在代码后面几行我想将某人的名字存储到缓冲区中。我应该去char person_name[25] 还是只是重复使用journal_name[25]

问题是每个阅读代码的人(几周后我也是)必须理解 journal_name 现在实际上是 person_name

但相反的论点是拥有两个缓冲区会增加空间使用率。所以最好用一个。

你怎么看这个问题?

谢谢,博达·赛多。

【问题讨论】:

  • Idk 关于常见的,这些天使用 50 字节的堆栈是非常无害的..
  • 如果是 PATH_MAX (2x4kb) 的两倍呢?
  • 我通常动态分配超过 64 字节的任何内容。话虽如此,8k仍然不是什么大不了的事。默认情况下,您有 1MB 的堆栈用于新线程。这是最低限度!

标签: c buffer naming


【解决方案1】:

如果你真的不想浪费内存,用 C 方式解决这个问题的方法是使用块来确定缓冲区的范围:

int main()
{
  {
    char journal_name[26];
    // use journal name
  }
  {
    char person_name[26];
    // use person name 
  }
}

编译器将为两者重用相同的内存位置,同时为您提供一个清晰易读的名称。

作为替代方案,将其命名为name 并将其用于两个<.>

【讨论】:

  • +1 这就是这样做的方法。但请注意,即使没有范围,编译器也可能足够聪明,可以确定在某个点之后不使用journal_name,因此它可以为person_name 使用相同的空间。即使有作用域,编译器也可以分配两个缓冲区。只需编写可读的代码,不要担心在这里或那里“浪费”堆栈上的 25 个字节,除非您正在为受严格约束的系统编写代码。
  • 像这样强制作用域非常有用,可惜很多人不知道这是可能的。
  • 顺便说一句:这在​​ C 中也有效(因为 {} 也在 C 中分隔范围)!
  • 编译器可能为两者重用相同的内存位置。它不是必需的,它是否真的这样做可能取决于优化设置。 (如果它在您的应用程序中真的很重要,确定的方法是查看生成的代码......)
  • {char b1[750*1024];char b2[751*1024];sprintf(b1, "%d", 1);sprintf(b2,"%d", 2);}{char b2[751*1024];sprintf(b2,"%d", 2);} 崩溃。 {char b1[750*1024];sprintf(b1, "%d", 1);}{char b2[751*1024];sprintf(b2,"%d", 2);} 工作正常。这是在 MSVC 10 下,发布模式。
【解决方案2】:

这里确实有一些代码。不过有几点需要注意:

保持标识符与您的对象分离。称它为scratchpad 或其他任何名称。此外,从外观上看,这个字符数组不是动态分配的。这意味着您必须分配足够大的便签本才能重用它们。

一个更好的方法可能是让你的函数更短:一个函数最好一次只做一件事。看看你是否可以分手并仍然面对问题。

【讨论】:

  • +1,这也是我的答案。我也想为do one thing at a time 加1,但我只能加1 分。
  • @Dacav:这也是我没有提出范围强制解决方案的原因:从某种意义上说,这不是一个解决方案,因为您仍在分配两个缓冲区,如果您分配了,则将它们分开范围只是继续,添加几行并编写一个函数!一个直接的优势是编写测试用例,随后的测试变得微不足道。
  • scratchpad_256b 如果是 256 字节呢?
  • @supercat:我尽量避免匈牙利符号的任何变化。恕我直言,大多数现代 IDE 都没有必要使用这种风格,而且我个人觉得它很刺耳。
  • 我通常不在标识符名称中使用类型,除非在几个标识符很可能主要通过类型来区分的情况下,或者在标识符没有其他任何东西可以指示它是什么类型的情况下。一个名为“scratchpad”之类的全局变量过于模糊,不知道它可以保存什么。
【解决方案3】:

作为之前(好的)答案的替代方案,那么

char buffer[25];

char* journal_name = buffer;

后来

char* person_name = buffer;

可以吗?

【讨论】:

  • 我不喜欢它。在同一个函数中,同一内存空间的两个不同含义的名称可能很容易造成混淆。 printf("%s has journal named %s", person_name, journal_name);。它确实看起来好像它们代表不同的事物。
【解决方案4】:

如果两个缓冲区都是自动的,为什么不使用它呢? 大多数编译器都会通过重用内存来正确处理这个问题。 但你保持可读性。

{
    char journal_name[25];
    /*
        Your code which uses journal_name..
    */
}
{
    char person_name[25];
    /*
        Your code which uses person_name...
    */
}

顺便说一句,即使你的编译器很笨而且你的内存非常低,你也可以使用联合,但为了可读性而保留不同的名称。使用相同的变量是最糟糕的方式。

【讨论】:

  • 这是我第一次看到这种将缓冲区分隔在单独范围内的模式。你从哪里学来的?
  • ua.linkedin.com/in/romannikitchenko - 实际上在 C 代码优化方面发挥了很大作用。这是我离开 MindSpeed 时的告别 ARM 培训演示(查看完整的个人资料,然后是 I-box 文件)。我包括了几种这样的技术。
  • 可以分享一下网址吗?我没有linkedin账户。 :(
【解决方案5】:

请使用person_name[25]。没有人喜欢难以阅读的代码。就内存而言,它对您的程序没有任何作用。请以可读的方式进行。

【讨论】:

    【解决方案6】:

    出于您在问题中提到的原因,您应该始终(除非您非常内存非常紧张)在编写代码时追求可读性和可维护性。

    25 个字符(除非这只是一个示例)不会“破坏银行”,但如果内存非常宝贵,您可以为 journal_name 动态分配存储空间,然后在完成后释放它在为person_name 动态分配存储之前使用它。虽然有指向数组的指针的“开销”。

    另一种方法是在数组上使用本地范围:

    void myMethod()
    {
        ... some code
        {
            char journal_name[25];
            ... some more code
        }
        ... even more code
        {
            char person_name[25];
            ... yet more code
        }
    }
    

    虽然即使使用这个伪代码,该方法也会变得很长,并且会受益于重构为不会出现此问题的子例程。

    【讨论】:

      【解决方案7】:

      如果您担心内存问题,并且我怀疑 25 字节是否会成为问题,那么您可以使用 mallocfree,然后您只需为指针使用额外的 4-8 字节。

      但是,正如其他人所提到的,可读性很重要,您可能希望分解您的函数,以便将两个缓冲区用于实际上提供更多关于其用途的指示的函数中。

      更新:

      现在,我有一个名为 buffer 的缓冲区,例如,我将使用它来读取文件,然后我将使用传递的函数指针来解析结果,以便函数读取文件, 并适当地处理它,这样缓冲区就不会被填充,然后我必须记住它不应该被覆盖。

      因此,当从套接字或文件读取时,重用缓冲区可能很有用,但您希望本地化此缓冲区的使用,否则您可能会遇到竞争条件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-27
        • 1970-01-01
        • 2021-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多