【问题标题】:C - unsigned int doesn't get the correct value on assignmentC - unsigned int 在赋值时没有得到正确的值
【发布时间】:2012-12-13 06:01:57
【问题描述】:

这是来自 gdb:

22      database->size = size;
(gdb) n
23      return database;
(gdb) p size
$6 = 1401
(gdb) p database->size
$7 = 3086862424
(gdb) p &size
$8 = (unsigned int *) 0xbffff050
(gdb) p &database->size
$9 = (unsigned int *) 0xb7fc6ff8

这是来自代码:

typedef struct _DATABASE {
    RESULT* res;
    unsigned int size;
} DATABASE;

....
....

DATABASE* alloc_database(unsigned int size, DATABASE* database)
{
    database = (DATABASE*) malloc (sizeof(DATABASE));
    if (!database) return NULL;
    database->res = (RESULT*) malloc (sizeof(RESULT) * size);
    if (!database->res) {
        free_database(database);
        return NULL;
    }
    memset(database->res, 0, sizeof(RESULT) * size);
    database->size = size;
    return database;
}

你可以看到,database->size 和 size 都来自 (unsigned int) 类型,在代码和 gdb 中,但由于某种原因,赋值后的值不同。

有人知道这是什么原因吗?

【问题讨论】:

  • 听说过calloc()吗?它确实在一个函数调用中分配和归零——并且可以使用最有效的归零,因为它知道数据在memset() 没有对齐的地方对齐。
  • 你确定你的代码是在没有优化的情况下编译的吗?
  • 调用函数长什么样子?
  • @JonathanLeffler:我不认为对齐是calloc 擅长的地方; memset 中唯一重要的位置错位开销是n 的微小值,其中启动开销占主导地位。对于大的n,它会迷失在噪音中。 calloc 真正的性能优势在于它有时可以知道内存已预置零(例如,当通过新的 mmap 获得时),因此完全避免了零填充操作。
  • 是的,和乔纳森说的一样。使用calloc,但也使用适当的类型size_t 而不是unsigned int。这将使程序更具可移植性。您也不需要在 C 中从 malloc 转换返回值。如果您的第二个 malloc 失败,您调用 free_database() 并使用未初始化的结构,这可能会出现问题。

标签: c gdb variable-assignment unsigned-integer


【解决方案1】:

数据库是函数alloc_database 的本地数据库。您将 malloc 的结果分配给它,但此分配是函数的本地分配。返回后,数据库返回到调用函数时的值。请注意,在 gdb 中,您在返回后检查 database->size 的值。所以你在数据库的值在函数之外的范围内检查它。

你有两个选择:

  1. 将函数更改为仅接收大小参数,分配给本地并返回它。然后就可以赋值返回值并在gdb中查看:

  2. 如果要在数据库参数中返回结果,则需要传递一个指向数据库指针的指针。

这是选项 2 的代码:

DATABASE* alloc_database(unsigned int size, DATABASE** database)
{
    *database = (DATABASE*) malloc (sizeof(DATABASE));
    if (! *database) return NULL;
    (*database)->res = (RESULT*) malloc (sizeof(RESULT) * size);
    if (!(*database)->res) {
        free_database((database);
        *database = NULL;
        return NULL;
    }
    memset((*database)->res, 0, sizeof(RESULT) * size);
    (*database)->size = size;
    return (*database);
}

附: אהבה לא באה בחינם...

【讨论】:

  • 好吧,如果它作为返回值传回,应该没问题。如果调用代码期望它被填写,那么您的解决方案很好[我尝试编辑它以使布局正确,但不知何故,它不喜欢它。我会再去一次。 [再一次,问题很可能出在我们看不到的代码中 - 80% 规则适用]
  • 只是进一步说明。既传递一个指向指针的指针,又返回数据库指针是没有意义的。
  • +1 用于发现正确的问题并提供解决方案。 OP 很可能会使用相同的 DB 指针反复调用它,如果是这样,它(以及它们通过推理)仍然会泄漏内存,就像它之前那样。但是,您只能做很多事情来保护某人免受自己的伤害。 PS:我也更喜欢 out-params 来返回结果。
  • @grebulon。 '请注意,在 gdb 中,您检查 database->size 的值,返回后' 不,他仍在 alloc_database() 的框架中。
  • grebulon,感谢您的回复和解决方案。我的代码几乎没有问题,这就是其中之一。正如 fizzer 所提到的,gdb 范围与我将值分配给 database->size 的范围相同(即在 alloc_database() 中),这就是我发布这个问题的原因。很抱歉没有说清楚。我已经从头开始重写了我的代码,所以我不再遇到问题,但问题仍然存在...... תתפלא :)
猜你喜欢
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 2011-05-02
  • 2019-07-20
  • 1970-01-01
  • 2022-10-19
  • 2022-08-16
  • 2021-05-28
相关资源
最近更新 更多