在C中声明函数内的结构

时间:2009-03-25 10:52:24

标签: c optimization data-structures

我有一个只有一个功能必须访问的结构。该函数将诸如“k,K,kb,KB,m,M,mb,MB,...”之类的标记转换为实际单位。这样做的目的是简化配置文件。

所以,假设我们有:

static uint32_t real_unit(const char *str)
{
    struct u2type {
      char key[3];
      uint32_t val;
    } const u2types[] = {
       { "k", KB_UNIT },
       { "K", KB_UNIT },
       { "kb", KB_UNIT },
       { "KB", KB_UNIT },
       { "m", MB_UNIT },
       { "M", MB_UNIT },
       { "mb", MB_UNIT },
       { "MB", MB_UNIT },
       { "g", GB_UNIT },
       { "G", GB_UNIT },
       { "gb", GB_UNIT },
       { "GB", GB_UNIT },
       { { 0 }, 0 }
    };

    ... code to look up str ...
}

我见过其他程序,其中struct u2type将被声明为静态(同样,在函数内),我看不出它是如何有用的。结构不会改变,每次输入函数时结构总是相同的。这就是为什么我把它变成了常量。

然而,我看到很多人在范围很明显的函数中执行statc struct foo {...} const foos [] = {...}。

这样做有什么好处吗?在尝试使用像这样的优化问题之前,我尝试研究ASM输出,但我不是装配大师:)

修改

是的,我知道这种方法闻起来像脚。有些项目只有奇怪的要求(通常由奇数人强制要求)。然而,这个问题与功能的使用完全分开。

6 个答案:

答案 0 :(得分:13)

使它成为常量并使其静态做两件事。

  • 如果是const,则每个函数调用都会获得自己不可更改的struct
  • 实例
  • 如果它是静态的,则在所有函数调用中共享一个可更改的struct实例

听起来好像你想要的是一个静态和const的结构实例,这是一个合理的事情。

性能方面,静态版本应略有优势,因为struct实例的构造只会执行一次。

答案 1 :(得分:5)

如果您声明您的数组是静态的,它将被放置在可执行文件的数据部分中并且只初始化一次(在第一次访问时)或者甚至没有(它可能已在可执行文件中初始化)。

如果没有静态,数据将位于每个函数调用的堆栈中,并在每次调用函数时初始化。

只是有点挑剔,当你说你看到struct u2type是静态的代码时,这不是真的。尽管静态存储说明符出现在struct之前,但它确实适用于变量,在本例中是数组。即使有了

static struct foo { ... } foos [] = { ... };

然后你可以做

struct foo foo1={ ... };

foo1将是一个自动变量。

答案 2 :(得分:0)

如果在函数中声明变量static,则仅在第一次输入函数时初始化一次。如果您将其声明为非静态,则每次输入函数时都会初始化它。

在你的情况下,它可以略有不同。使用 static ,阵列将在静态存储中分配并初始化不超过一次。如果没有 static ,它将在堆栈上分配,并且每次调用该函数。

答案 3 :(得分:0)

在堆栈上分配局部变量或常量。它们的存在仅在函数执行期间持续,并且一旦函数返回它们的值就会丢失。每次调用函数时都会进行分配和分配。

声明局部变量或常量静态意味着它的值将从一次调用到下一次调用。这是通过全局分配而不是堆栈来实现的。分配和分配只执行一次,如果频繁调用的函数中的大数据结构可能会导致性能提升。

答案 4 :(得分:0)

Eeeww。至少将您的函数名称更改为“case_insensitive_guess_unit”。其中大多数都不是“真正的”单位,而那些('K'例如开尔文不是公斤,'b'通常是位和'B'字节)不是你要返回的单位。

如果规格是k [b] - > 1000,m [b] - > 1000000等,然后一个简单的if / else可能更快更清洁。

答案 5 :(得分:0)

...

// so, do you want odor-free, or fast ?
switch (str[0]){
case 'g': case 'G':
  return GB_UNIT;
case 'k': case 'K':
  return KB_UNIT;
case 'm': case 'M':
  return MB_UNIT;
}