1

我有一个main方法看起来像这样。

    struct list *l = array_list();
    if (l == NULL) {
        return EXIT_FAILURE;
    }
    srand(time(NULL));
    int size = 4;
    for (int i = 0; i < size; i++) {
        int *d = malloc(sizeof(int));
        *d = rand();
        list_insert_last(l, d);
        printf("inserted: %d\n", *d);
    }
    printf("size: %zu\n", list_size(l));
    for (int i = 0; i < size; i++) {
        int *d = list_delete_first(l);
        printf("deleted: %d\n", *d);
        free(d);
    }
    printf("size: %zu\n", list_size(l));
    array_list_free(l);
    return EXIT_SUCCESS;

我的问题是,即使我已经标记premature-optimizationint *d变量。

一旦退出循环并重用它会更好地声明变量吗?

    struct list *l = array_list();
    if (l == NULL) {
        return EXIT_FAILURE;
    }
    srand(time(NULL));
    int size = 4;
    int *d; // declare once
    for (int i = 0; i < size; i++) {
        d = malloc(sizeof(int)); // reuse it
        *d = rand();
        list_insert_last(l, d);
        printf("inserted: %d\n", *d);
    }
    printf("size: %zu\n", list_size(l));
    for (int i = 0; i < size; i++) {
        d = list_delete_first(l); // reuse it
        printf("deleted: %d\n", *d);
        free(d);
    }
    printf("size: %zu\n", list_size(l));
    array_list_free(l);
    return EXIT_SUCCESS;
4

2 回答 2

1

我认为任何现代编译器都会在某些时候涉及静态单一赋值表示,因此它不会对生成的代码产生影响。

我更喜欢您的第一个示例,但这 100% 是为了人类读者的利益,他们不必怀疑d以后是否使用。编译器将进行足够的分析以知道它们是等价的。

于 2021-08-09T07:02:10.750 回答
1

它没有任何区别。C 代码中变量声明的位置通常与机器代码中的分配位置不同。所以这确实是“未成熟的优化”。

当我反汇编您的代码时,我得到相同的机器代码d = mallocint* d = malloc. 根据size,编译器甚至可能在优化期间展开整个循环。在任何一种情况下,d都可能在 CPU 索引寄存器中分配,这与分配速度一样快。(大约 2-3 个周期或其他取决于 ISA。)

然而,通常最好的做法是尽可能减少变量的范围,使代码更具可读性并减少命名空间的混乱。因此本地int *d = malloc是正确的形式。(作为奖励,C90 也兼容。)


现在,如果你真的关心性能,这段代码的主要瓶颈是 I/O printf,它比分配单个int变量要慢得多。

类似地,重复调用mallocin 循环速度要慢得多。它还会导致不必要的堆碎片并阻止有效的数据缓存使用,因为分配的内存到处都是。

rand() 调用也可能有点慢,这取决于 C lib 实现。

于 2021-08-09T08:53:06.257 回答