使用GCC编译C代码时传参引发段错误,C++编译无异常
问题描述
我是有经验的C开发者,学习C语言时开发Fastcomm FSCC卡测试工具。最初用C引用传参、g++编译时无段错误且输出正常,改用gcc编译C代码后,编译无警告但运行出现段错误。经gdb调试确认,段错误由update_all_registers函数中访问结构体成员的操作导致。补充关键信息:FSCC_REGISTERS_INIT调用完全符合预期,会将整个结构体填充为'-1',段错误发生在访问结构体单个成员时。请问我的传参方式是否有误?
原代码
#include <fcntl.h> #include <unistd.h> #include <fscc.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <ncurses.h> int64_t get_current_time_ms() { struct timeval tv; gettimeofday(&tv, NULL); return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; } void update_all_registers(int fd, struct fscc_registers* regs) { FSCC_REGISTERS_INIT(regs); regs->CMDR = FSCC_UPDATE_VALUE; regs->STAR = FSCC_UPDATE_VALUE; regs->CCR0 = FSCC_UPDATE_VALUE; regs->CCR1 = FSCC_UPDATE_VALUE; regs->CCR2 = FSCC_UPDATE_VALUE; regs->BGR = FSCC_UPDATE_VALUE; regs->SSR = FSCC_UPDATE_VALUE; regs->SMR = FSCC_UPDATE_VALUE; regs->TSR = FSCC_UPDATE_VALUE; regs->TMR = FSCC_UPDATE_VALUE; regs->RAR = FSCC_UPDATE_VALUE; regs->RAMR = FSCC_UPDATE_VALUE; regs->PPR = FSCC_UPDATE_VALUE; regs->TCR = FSCC_UPDATE_VALUE; regs->VSTR = FSCC_UPDATE_VALUE; ioctl(fd, FSCC_GET_REGISTERS, ®s); } void print_registers(struct fscc_registers* regs) { printf("%.10llu 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x " "0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", get_current_time_ms(), regs->CMDR, regs->STAR, regs->CCR0, regs->CCR1, regs->CCR2, regs->BGR, regs->SSR, regs->SMR, regs->TSR, regs->TMR, regs->RAR, regs->RAMR, regs->PPR, regs->TCR, regs->VSTR); } int main(void) { int fd = 0; struct fscc_registers regs; fd = open("/dev/fscc0", O_RDWR); if (fd == -1) { perror("open"); return EXIT_FAILURE; } FSCC_REGISTERS_INIT(regs); ioctl(fd, FSCC_GET_REGISTERS, ®s); printf("TS (ms) CMDR STAR CCR0 CCR1 CCR2 BGR" " SSR SMR TSR TMR RAR" " RAMR PPR TCR VSTR\n"); print_registers(®s); char odata[] = "This is a test"; write(fd, odata, sizeof(odata)); update_all_registers(fd, ®s); print_registers(®s); close(fd); return 0; }
问题根源与修正
你的传参逻辑存在两处关键错误,都集中在update_all_registers函数中:
1. FSCC_REGISTERS_INIT参数类型错误
FSCC_REGISTERS_INIT宏的设计目标是初始化结构体实例,而非结构体指针。你在main函数中调用FSCC_REGISTERS_INIT(regs)是正确的,但在update_all_registers中传入指针regs,会导致宏直接修改指针变量本身的内存(将其填充为'-1'),破坏了指针的有效地址。后续访问regs->CMDR时,指针已经指向非法内存,触发段错误。
修正:将宏调用改为对指针指向的结构体实例初始化:
FSCC_REGISTERS_INIT(*regs);
2. ioctl参数传递错误
FSCC_GET_REGISTERS命令要求传入struct fscc_registers*类型的指针,但你调用ioctl(fd, FSCC_GET_REGISTERS, ®s)时,regs本身已经是结构体指针,取地址后变成了二级指针struct fscc_registers**,内核无法正确解析这个地址,会导致后续操作异常。
修正:直接传入指针regs:
ioctl(fd, FSCC_GET_REGISTERS, regs);
修正后的update_all_registers函数
void update_all_registers(int fd, struct fscc_registers* regs) { FSCC_REGISTERS_INIT(*regs); regs->CMDR = FSCC_UPDATE_VALUE; regs->STAR = FSCC_UPDATE_VALUE; regs->CCR0 = FSCC_UPDATE_VALUE; regs->CCR1 = FSCC_UPDATE_VALUE; regs->CCR2 = FSCC_UPDATE_VALUE; regs->BGR = FSCC_UPDATE_VALUE; regs->SSR = FSCC_UPDATE_VALUE; regs->SMR = FSCC_UPDATE_VALUE; regs->TSR = FSCC_UPDATE_VALUE; regs->TMR = FSCC_UPDATE_VALUE; regs->RAR = FSCC_UPDATE_VALUE; regs->RAMR = FSCC_UPDATE_VALUE; regs->PPR = FSCC_UPDATE_VALUE; regs->TCR = FSCC_UPDATE_VALUE; regs->VSTR = FSCC_UPDATE_VALUE; ioctl(fd, FSCC_GET_REGISTERS, regs); }
内容的提问来源于stack exchange,提问作者mreff555

