【问题标题】:How Object files get linked in C? Explain this particular situation目标文件如何在 C 中链接?解释这种特殊情况
【发布时间】:2017-03-17 21:05:21
【问题描述】:

为什么它们打印不同的值。请详细说明。 一个文件是:

    /* boo.c */
#include <stdio.h>
char main;
void p2()
{
printf("0x%X\n", main);
}

另一个文件是:

/* foo6.c */ 
void p2(void);

int main()
{
    char ch = main;
    p2();
    printf("Main address is 0x%x\n",main);
    printf("Char value is 0x%x\n",ch);
    return 0;
}

我希望 p2 和 char ch 打印相同的值,但它们打印的值非常不同。 输出是:

0x55
Main address is 0x401110
Char value is 0x10

我无法得出这些值背后的原因(Main 和 char 值按预期工作,但不是我前面提到的 p2 输出)

【问题讨论】:

  • char 可能是 8 位且已签名。指针可能是 32/64 位且无符号的。去图吧。
  • 注意“Char”的值如何与“Main”的最后一个字节(2个半字节)相同,即0x10
  • 在一个目标文件中,main 是一个字符,而在另一个目标文件中是一个函数指针。我认为没有定义将两者联系在一起。

标签: c pointers memory-address


【解决方案1】:

char ch = main; 只是将指针截断为一个字符。定义了实现,但获得较低的 8 位是有意义的。

现在,另一个编译单元中的char main(未初始化)通过将函数指针直接映射到char 上来欺骗编译器,无需任何转换:这是未定义的行为

(并且printf使用的格式与数据类型不匹配...)

试试看:char main=12; 你会得到一个多重定义的符号main...

【讨论】:

  • 未定义的行为确实是底线。此外,应该注意的是,即使使用原始代码,该行为也是未定义的,其中 boo.c 没有为其main 提供初始化程序。
【解决方案2】:

它确实是未定义的行为,只是补充一下 - 为什么你会从 p2 看到 0x55,看看反汇编:

p2:
...
0x40052a: movzx   eax,BYTE PTR [rip+0x17]        # 0x400548 <main>
...
main:
0x400548: push    rbp

gcc 生成的代码在函数主地址获取第一个字节,实际上它是push rbp 的操作码,即0x55

您可以像这样重写 p2 代码以更好地理解它:

int main();
void p2() {
    char t = ((char*)&main)[0];
    printf("%x\n", t);
}

【讨论】:

    猜你喜欢
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    相关资源
    最近更新 更多