C 在函数调用期间获取不正确的变量地址

C 在函数调用期间获取不正确的变量地址,c,C,在进行函数调用时,我丢失了(全局)变量(在共享对象中定义)的地址。为了证明这一点,我特意将变量num_accounts的值设置为55,当函数get_num_accounts()开始执行时,错误地接收到指向该变量的指针。我的证据是gdb会议: accounts_init () at accounts.c:31 31 err_code=read_accounts(); (gdb) print num_accounts $1 = 0 (gdb) print &num_accounts

在进行函数调用时,我丢失了(全局)变量(在共享对象中定义)的地址。为了证明这一点,我特意将变量num_accounts的值设置为55,当函数get_num_accounts()开始执行时,错误地接收到指向该变量的指针。我的证据是gdb会议:

accounts_init () at accounts.c:31
31      err_code=read_accounts();
(gdb) print num_accounts
$1 = 0
(gdb) print &num_accounts
$2 = (account_idx_t *) 0x7ffff767c640 <num_accounts>
(gdb) set var num_accounts=55
(gdb) print num_accounts
$3 = 55
(gdb) s
read_accounts () at accounts.c:66
66      err_code=get_num_accounts(&num_accounts);
(gdb) s
get_num_accounts (num_accounts_ptr=0x604780 <num_accounts>) at accounts.c:119
119     *num_accounts_ptr=0;
(gdb) print num_accounts
$4 = 55
(gdb) print *num_accounts_ptr
$5 = 0
(gdb) 
(gdb) print num_accounts_ptr
$6 = (account_idx_t *) 0x604780 <num_accounts>
(gdb) 
账户类型定义为:

typedef         unsigned short          account_idx_t;
全局变量num_accounts在accounts.c文件开头定义:

account_idx_t       num_accounts=0;
基本上,函数所做的是在读取文件之前获取文件的大小并计算文件包含的记录数。(这是一个数据库)

这是调用代码,调用get_num_accounts()函数:

err_code_t accounts_init(void) {
    err_code_t err_code;

    err_code=read_accounts();
    if (err_code!=ERR_NO_ERROR) return err_code;

    return ERR_NO_ERROR;
}
err_code_t read_accounts(void) {
    err_code_t err_code;
    int ret;

    err_code=get_num_accounts(&num_accounts);
    if (err_code!=ERR_NO_ERROR) return err_code;
    if (num_accounts==0) return ERR_NO_ERROR;

    int fd=open(filename_buf,O_RDONLY); // filename_buf is global, it holds filename from previous call
    if (fd==-1) {
        return ERR_SYS_ERROR;
    }
    ret=read(fd,accounts,sizeof(tbl_account_t)*num_accounts);
    if (ret==-1) {
        return ERR_SYS_ERROR;
    }
    ret=close(fd);  // TO_DO: validate return value of close(fd)
    if (ret==-1) {
        return ERR_SYS_ERROR;
    }
    return ERR_NO_ERROR;
}
我正在使用-fPIC标志编译库:

[niko@dev1 src]$ make accounts.o
gcc -g -ffunction-sections -fdata-sections -Wall -Wextra -Wunreachable-code -Wmissing-prototypes -Wmissing-declarations -Wunused -Winline -Wstrict-prototypes -Wimplicit-function-declaration -Wformat -D_GNU_SOURCE -fshort-enums -fPIC -c accounts.c
源代码中没有另一个“num_accounts”符号,我仔细检查了一下:

[niko@dev1 src]$ nm *o|grep num_accounts 
0000000000000000 T get_num_accounts
0000000000000000 B num_accounts
[niko@dev1 src]$ 

有关于进一步调试步骤的建议吗?

gdb正在查看的可执行映像中有两个不同的符号,称为
num\u accounts
。gdb直接告诉您,每当您告诉它打印具有指针类型值的内容时,gdb都会在可执行文件的符号表中对该地址进行反向查找,如果它找到某个内容,则会在中打印符号的名称。因此,当您执行gdb命令时:

(gdb) print &num_accounts
$2 = (account_idx_t *) 0x7ffff767c640 <num_accounts>
告诉您
0x604780
指向一个也称为
num\u accounts
的符号


现在的问题是你如何得到两个同名的符号。大地址
0x7ffff767c640
将位于共享库中,因为共享库在这样的地址加载。小地址
0x604780
在基本可执行文件中。

我不擅长GDB。所以这可能是一个愚蠢的问题。您是要进入
get\u num\u accounts
还是跳过。如果您在阅读
*num\u accounts\u ptr
时正在跳过,则它超出了范围。@莫特科恩使用“s”命令跨过它是命令“n”,很抱歉再次询问,但0x7ffff767c640在我看来不是有效地址。有点太高了,不是吗?@MotKohn是的,但它是一个共享对象,它有一个不同的(虚拟)地址空间,可能与主程序的数据段不同AFAIK在我的代码中没有malloc(),所有变量都是静态分配的,所以,不可能有这种类型的bug我想输出中会有什么“(num_accounts_ptr=0x604780)”GDB的意思是num_accounts_ptr指向“num_accounts”,这是一个全局变量。事实上,我将全局变量本身作为参数传递。我不需要这样做,因为变量是全局的,我可以在任何地方访问它,但是将它传入参数也是有效的。我没有重复的符号,否则我将无法在共享库和可执行文件之间链接重复的符号,除非您使用适当的链接标志专门请求它,否则不会阻止链接。尝试在可执行库和共享库上运行nm,并查看每个库中定义了哪些符号。
(gdb) print &num_accounts
$2 = (account_idx_t *) 0x7ffff767c640 <num_accounts>
(gdb) print num_accounts_ptr
$6 = (account_idx_t *) 0x604780 <num_accounts>