【问题标题】:C program, two variable with same name in different source codes without externC程序,不同源代码中两个同名变量,不带extern
【发布时间】:2020-12-20 09:39:39
【问题描述】:

我有一个奇怪的问题。 这是两个源代码。

/*---main.c---*/
#include <stdio.h>
int d=100;
int x=200;
void p1(void);
int main() {
    p1();
    printf("d=%d,x=%d\n",d,x);
    return 0;
}
/*---p1.c---*/
double d;
void p1() {
    d=1.0;
}

我编译代码和链接。 我收到警告:

/usr/bin/ld: Warning: alignment 4 of symbol `d' in /tmp/ccuZEbnu.o is smaller than 8 in /tmp/ccrTyML7.o

我执行程序并得到结果d=0,x=1072693248,为什么不是d=100,x=200? 这太奇怪了,我无法理解。我尝试打印dx的地址,发现两个源代码中变量d的地址完全一样。我认为不同源代码中的两个变量d应该是不同的,因为它没有extern

我是新手。对不起我的英语不好。提前感谢您的帮助。

【问题讨论】:

  • C 和 C++ 是非常不同的语言。请不要同时标记两者,除非您的问题专门针对它们的差异。
  • 函数中不存在返回。您还需要定义函数的输出数据类型 ex) int user_function () { return int type output}
  • 您可能想了解static 关键字的用途。
  • @Gerhardh 我知道了,变量默认是extern
  • @guapi,你可以发布一个答案。

标签: c gcc symbols


【解决方案1】:

我尝试在 STFW 之后解释这个问题。 首先,全局变量默认为extern,所以两个变量的地址相同。 d 是什么类型的?我认为应该是int。这与链接阶段的强符号和弱符号有关。我尝试printf("sizeof(d)=%u\n", sizeof(d)),然后我会得到结果:sizeof(d)=4。我还打印了dx 的地址,它们相差4 个字节。 但是如何解释p1.c 中的行为?我给出我的理解:

void p1()
{
    *(double *)(&d) = 1.0;
}

由于dx的地址相差4个字节,而double的大小是8个字节,所以这段代码同时改变了x的值。 如有错误,请指出。

【讨论】:

    【解决方案2】:

    程序具有未定义的行为,因为具有外部链接的名称 d 在同一文件范围内定义了两次。

    所以链接器似乎只定义了外部变量 d 声明为具有double 类型。在这种情况下,由于double 类型的大小等于8,那么大小等于4int 类型的对象占用分配的内存的一半,由于以下原因设置为零本次作业

    d=1.0;
    

    这是一个演示程序,展示了如何在内部表示例如具有值 1.0 的 double 类型的对象。

    #include <stdio.h>
    
    int main(void) 
    {
        double d = 1.0;
        
        for ( char *p = ( char * )&d; p < ( char * )&d + sizeof( double ); ++p )
        {
            char c = *p >> 4 & 0x0f;
            if ( c > 9 ) c = c - 10 + 'A';
            else c += '0';
            putchar( c );
            c = *p & 0x0f;
            if ( c > 9 ) c = c - 10 + 'A';
            else c += '0';
            putchar( c );
        }
    
        putchar( '\n' );
        
        return 0;
    }
    

    程序输出是

    000000000000F03F
    

    如您所见,double 数的内部表示的长度等于 4 字节的一部分由全零组成。

    在生成的对象代码中选择这部分作为int类型的对象。

    现在,如果您要像这样以十六进制输出值 x=1072693248

    printf( "%x\n",  1072693248u );
    

    你会得到

    3ff00000
    

    也就是双数d的内部表示的后半部分。

    因此,要么在其中一个模块中重命名变量 d,要么使用存储说明符 static 使用内部链接声明它。

    【讨论】:

    • 链接器不应该只是抱怨d被多重定义吗?
    • @Jabberwocky 是的,应该。但我们不知道该消息是否被用户忽略。:) 结果程序具有未定义的行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    相关资源
    最近更新 更多