You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言多源文件中union跨文件访问无法读取一致值问题

跨源文件访问联合体读取值不一致问题

问题现象

项目包含main.c、loader.c两个源文件,以及定义联合体类型的comp.h头文件,预期实现两个源文件访问同一个联合体实例完成读写。实际运行时,loader()函数内写入数据后打印可确认写入成功,但回到main函数执行读操作时,对应位置值全为0。
相关代码如下:

main.c

#include <stdio.h>
#include "comp.h"

union memory mem1;

int main() {
    int choice;
    unsigned int addlo, addhi;
    unsigned short data;
    int k;
    while (1)
    {
        printf("Please Select a Command\n");
        printf("0. Exit\n");
        printf("1. Load S-Record\n");
        printf("2. Read Memory\n");
        if(1 != scanf("%d", &choice) == 1)
        {
            fprintf(stderr, "Failed to read command.\n");
            break;
        }
        else if(choice == 0)
        {
            break;
        }
        else if(choice == 1)
        {
            loader();
        }
        else if(choice == 2)
        {
            for(k = 1; k<= 10; k++)
            {
                printf("k: %x mem: %x\n", k, mem1.byte[k]);
            }
        }

    }
    return 0;
}

comp.h

void loader(void);
union memory{
    unsigned char byte[0x10000];
    unsigned short word[0x8000];
};

loader.c

#include <stdio.h>
#include "comp.h"

union memory mem;

void loader (void){
    
    int i;
    mem.byte[0] = 0xA1;
    mem.byte[1] = 0xA2;
    for(i = 0; i<= 10; i++)
    {
        printf("i: %x mem: %x\n", i, mem.byte[i]);
    }
    
}

运行输出:

Please Select a Command
0. Exit
1. Load S-Record
2. Read Memory
1
i: 0 mem: a1
i: 1 mem: a2
i: 2 mem: 0
i: 3 mem: 0
i: 4 mem: 0
i: 5 mem: 0
i: 6 mem: 0
i: 7 mem: 0
i: 8 mem: 0
i: 9 mem: 0
i: a mem: 0
Please Select a Command
0. Exit
1. Load S-Record
2. Read Memory
2
k: 1 mem: 0
k: 2 mem: 0
k: 3 mem: 0
k: 4 mem: 0
k: 5 mem: 0
k: 6 mem: 0
k: 7 mem: 0
k: 8 mem: 0
k: 9 mem: 0
k: a mem: 0
Please Select a Command
0. Exit
1. Load S-Record
2. Read Memory

根因分析

  • 核心问题是定义了两个完全独立的全局联合体实例:main.c中定义的mem1和loader.c中定义的mem是分配在不同内存地址的两个独立变量,loader()写入的是mem,main函数读取的是从未写入过的mem1,自然读不到正确值。全局变量如果没有手动初始化会被默认填0,这就是main里读出来全是0的原因。
  • 代码里还有两个附加bug:
    • main中读内存的循环从k=1开始,就算访问的是正确实例,也读不到下标0位置写入的0xA1
    • scanf的判断逻辑写法错误,1 != scanf("%d", &choice) == 1的运算优先级不符合预期,无法正确判断输入是否失败
  • 不存在“写入数据没在两次菜单操作间留存”的问题:全局变量的生命周期覆盖整个程序运行周期,只要不主动覆写,写入的值会一直保留。

修复方案

按照C语言多文件编程的全局变量规范修改即可:

  1. 修改comp.h,添加全局联合体的外部声明,让所有包含该头文件的源文件都知道这个实例的存在:
    void loader(void);
    union memory{
        unsigned char byte[0x10000];
        unsigned short word[0x8000];
    };
    extern union memory mem; // 外部声明,不分配内存,仅告知编译器该变量在其他源文件中定义
    
  2. 全局变量只能在一个源文件中定义,删除main.c里的union memory mem1;,保留loader.c里的union memory mem;作为唯一的实例定义。
  3. 修改main函数里的访问逻辑,把读内存部分的mem1.byte[k]改成mem.byte[k],如果需要读取下标0的0xA1,把循环起始值改成k=0。
  4. 修正输入判断逻辑,把错误的判断改成:
    if(scanf("%d", &choice) != 1)
    {
        fprintf(stderr, "Failed to read command.\n");
        break;
    }
    

改完重新编译运行,loader写入的值就可以在main里正常读取到了。


内容的提问来源于stack exchange,提问作者JohnM Wall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 10:57:19