有效地在C中初始化数组/数据块

时间:2011-12-16 17:50:14

标签: c arrays pointers gcc initialization

我试图在C中初始化一个数组,并且对于每个元素,GCC正在生成一个mov指令(如果有许多要初始化的元素,这是一种低效的方法)。如何使用数组数据加载内存并从中返回指针而不是以这种方式初始化?

6:array.c       ****         int a[]={1,2,3,4,5,9};
26                      .loc 1 6 0
27 0008 C745E001        movl    $1, -32(%rbp)
27      000000
28 000f C745E402        movl    $2, -28(%rbp)
28      000000
29 0016 C745E803        movl    $3, -24(%rbp)
29      000000
30 001d C745EC04        movl    $4, -20(%rbp)
30      000000
31 0024 C745F005        movl    $5, -16(%rbp)
31      000000
32 002b C745F409        movl    $9, -12(%rbp)
32      000000

4 个答案:

答案 0 :(得分:3)

我相信以下内容可以解答您的问题“如何使用数组数据加载内存并从中返回指针?”:

int a_data[] = {1,2,3,4,5,9};

int main() {
  int *a = a_data;
}

这编译为:

        .data
a_data:
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   9

        .text
main:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movq    $a_data, -8(%rbp)
        leave
        ret
        .cfi_endproc

如您所见,这些值存在于数据段中,而main()只是指向数据的指针。

当然,如果你改变a[],那么下次你取a_data的地址时,这些突变仍会存在。如果您希望获得原始值,则应该复制a_data,而不是简单地使用指向它的指针。

答案 1 :(得分:1)

我认为a是一个局部变量,对吧?尝试声明数组静态 - 然后它的数据应该从文本块加载。然而,变量的含义及其初始化将会发生变化。

答案 2 :(得分:1)

根据您的需要,您有两个简单的选择:

1)使其静止

void bar(const int *);

void foo() {
    static int a[]={1,2,3,4,5,9};

    bar(a);
}

收益率 - 这只是对静态数据的引用。

foo:
.LFB0:
        .cfi_startproc
        movl    $a.1591, %edi
        jmp     bar
        .cfi_endproc
.LFE0:
        .size   foo, .-foo
        .data
        .align 16
        .type   a.1591, @object
        .size   a.1591, 24
a.1591:
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   9

另一种选择,如果您需要非静态或常量的数据。是拥有静态数据然后自己做一个memcpy将其移动到适当的位置。有趣的是,具有优化功能的gcc将使用各种策略将其复制到位。

void bar(const int *);

void foo() {
    static int s[]={1,2,3,4,5};
    int a[sizeof(s)/sizeof(s[0])];
    memcpy(a, s, sizeof(s));

    bar(a);
}

最重要的是,代码是必要的,因为数据的内存位置在编译时没有固定,因此某些代码需要将数据复制到内存中。

答案 3 :(得分:0)

如果a是全局或静态文件或函数范围,则数据将存储在二进制图像中。当应用程序启动时,运行时系统将把值加载到内存中。

int a[]={1,2,3,4,5,9};

static int a[]={1,2,3,4,5,9}; void func(void) { static int a[]={1,2,3,4,5,9}; }

如果a在函数级别声明为非静态:

void func(void) { static int a[]={1,2,3,4,5,9}; }

这些值不需要存储在可执行文件中,而是一系列存储在存储器中(即在堆栈中)。

无论哪种方式,都无法解决在初始化数组时必须将值加载到内存中的事实。

但是如果数组声明为

const int a[] = {1,2,3,5,9};

使用常量折叠编译单元,然后数组可能永远不存在(取决于文件范围和所有这些)。