gpt4 book ai didi

c - 在 C 中调用函数时出现段错误

转载 作者:可可西里 更新时间:2023-11-01 10:32:41 26 4
gpt4 key购买 nike

所以我正在构建一个虚拟机,并试图让它尽可能跨平台,突然遇到一个奇怪的错误。我的机器有一个let指令,它为机器内存中的一个变量分配内存,并为该变量赋值。简而言之,let 函数调用getAddress 来获取变量的地址。 getAddress 检查变量是否已定义,并返回地址。如果变量没有定义,getAddress调用memallocate为变量分配内存,并返回地址。这是函数的定义:

static uint16_t memallocate(Machine *m, char *symbol){
uint16_t allocationAddress = getFirstFree(*m);
SymbolTable *newSymbol = (SymbolTable *)malloc(sizeof(SymbolTable));
newSymbol->symbolName = strdup(symbol);
newSymbol->next = NULL;
newSymbol->mema = allocationAddress;
if(m->symbolTable==NULL){
m->symbolTable = newSymbol;
}
else{
SymbolTable *temp = m->symbolTable;
while(temp->next!=NULL)
temp = temp->next;
temp->next = newSymbol;
}
m->memory[allocationAddress].acquired = 1;
m->memory[allocationAddress].data.value = 0;
m->occupiedAddress++;
return allocationAddress;
}

uint16_t getAddress(Machine *m, char *symbol){
SymbolTable *table = m->symbolTable;
while(table!=NULL){
if(strcmp(symbol, table->symbolName)==0){
return table->mema;
}
table = table->next;
}
uint16_t address = memallocate(m, symbol); // Here is the segfault happening
return address;
}

此代码在 Linux 上编译和运行得很好,但在 Windows 上,我在 memallocate 调用中遇到段错误。由于 memallocate 直接传递了 getAddress 的参数,而且参数都是指针,所以它们不应该改变。但是在通过 CLion 进行调试时,我看到了 memallocate 调用的乱码参数,这表明存在某种堆栈违规(可能)。同样,它只发生在 Windows 中。谁能告诉我我的代码出了什么问题?该项目的完整代码可以在 GitHub 找到。 .

最佳答案

我获取了你的代码并通过 valgrind 在 linux 上运行它:

==13768== Conditional jump or move depends on uninitialised value(s)
==13768== at 0x109ABE: getAddress (in /home/vonaka/VirtualMachine/machine)
==13768== by 0x10B714: let (in /home/vonaka/VirtualMachine/machine)
==13768== by 0x109425: run (in /home/vonaka/VirtualMachine/machine)
==13768== by 0x109F64: main (in /home/vonaka/VirtualMachine/machine)
==13768== Uninitialised value was created by a heap allocation
==13768== at 0x4C2BE7F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd
==13768== by 0x109C2F: main (in /home/vonaka/VirtualMachine/machine)
==13768==

所以(幸运的是)这不是 Windows 特有的问题。诀窍是在第一次调用 getAddress 时(当 m->symbolTableNULL 时)你调用 getFirstFree(*m) memallocate开头,但是看这个函数:

static uint16_t getFirstFree(Machine m) {
uint16_t add = 0;
while(m.memory[add].acquired)
add++;
return add;
}

m.memory[i].acquired 对于 0number_of_instructions_in_your_input_file - 1 之间的 i 都是相等的在 writeInstruction 中将它们初始化为 1,但 m.memory[number_of_instructions_in_your_input_file].acquired 尚未初始化。

所以这样的事情会解决你的问题:

void writeInstruction(Machine *m, uint16_t add, Instruction ins) {
m->memory[add].acquired = 1;
m->memory[add].type = INSTRUCTION;
m->memory[add].data.instruction = ins;
m->occupiedAddress++;
if(add + 1 < NUM_MEM)
m->memory[add + 1].acquired = 0;
}

或者这可能更优雅(如果可行):

static uint16_t getFirstFree(Machine m) {
uint16_t add = 0;
while (m.memory[add].acquired && add < m.occupiedAddress)
add++;
return add;
}

编辑:

首先关于您的评论:

By default, the members of the structure is initialised as 0

这不是真的!

现在谈谈为什么在没有 malloc 的情况下出现段错误,以及它如何与 valgrind 的警告相关联。

你有 Machine 类型的变量 m 和堆栈中的一些其他变量,m 包含 Cell memory[NUM_MEM] 并且每个 Cell 中都有 acquired(未初始化!)。假设您的输入文件包含 88 条指令,因此前 88 条 acquired 将在 88 次 writeInstruction 调用后正确初始化。然后程序通过调用一些函数开始执行您的指令,包括 memallocategetFirstFree。在这个循环中:

while(m.memory[add].acquired)
add++;

对于任何 add m.memory[add].acquired 很可能不同于 0,所以一旦 add 等于 NUM_MEM 你有段错误。

为什么 malloc 没有发生这种情况?仅仅因为您很幸运(但不是运气),您的堆比堆栈“干净”。为什么它只发生在 Windows 中?因为这次你没那么幸运(我什至在 Windows 中都没有段错误)。

关于c - 在 C 中调用函数时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45742464/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com