繁体   English   中英

seekg() 似乎跳过预期的字符 position C++

[英]seekg() seeminlgy skipping characters past intended position C++

我一直在解析文件和使用 seekg() 时遇到问题。 每当在文件中达到某个字符时,我想循环直到满足条件。 循环在第一次迭代时工作正常,但是当它循环返回时,文件似乎跳过了一个字符并导致循环无法按预期运行。

具体来说,如果循环全部包含在文件的一行中,则循环可以正常工作,但当文件中的循环中至少有一个换行符时,循环会失败。

我应该提到我正在 Windows 上进行这项工作,我觉得问题出在 Windows 如何以\r\n结束行。

在循环返回后使用seekg(-2, std::ios::cur)可以解决开始循环条件后紧跟换行符的问题,但不适用于同一行中包含的循环。

代码的结构是让解释器 class 保存文件指针和相关变量,例如当前行和列。 这个 class 还有一个功能 map 定义如下:

// Define function type for command map
    typedef void (Interpreter::*function)(void);

    // Map for all the commands
    std::map<char, function> command_map = {
        {'+', increment_cell},
        {'-', decrement_cell},
        {'>', increment_ptr},
        {'<', decrement_ptr},
        {'.', output},
        {',', input},
        {'[', begin_loop},
        {']', end_loop},
        {' ', next_col},
        {'\n', next_line}
    };

它遍历每个字符,确定它是否具有以下 function 中的功能:

// Iterating through the file
void Interpreter::run() {
    char current_char;
    if(!this->file.eof() && this->file.good()) {
        
        while(this->file.get(current_char)) {

            // Make sure character is functional command (ie not a comment)
            if(this->command_map.find(current_char) != this->command_map.end()) {

                // Print the current command if in debug mode
                if(this->debug_mode && current_char != ' ' && current_char != '\n') {
                    std::cout << this->filename << ":" << this->line << ":" 
                              << this->column << ": " << current_char << std::endl;
                }

                // Execute the command
                (this->*(command_map[current_char]))();
            }

            // If it is not a functional command, it is a comment. The rest of the line is ignored
            else{
                std::string temp_line = "";
                std::getline(file, temp_line);
                this->line++;
                this->column = 0;
            }
            this->temp_pos = file.tellg();
            this->column++;
        }
    }

    else {
        std::cout << "Unable to find file " << this->filename << "." << std::endl;
        exit(1);
    }

    file.close();
}

循环的开始(由 '[' 字符表示)将开始循环 position 设置为this->temp_pos

void Interpreter::begin_loop() {
    this->loop_begin_pointer = this->temp_pos;
    this->loop_begin_line = this->line;
    this->loop_begin_col = this->column;
    this->run();
}

当到达循环结束(由']'字符表示)时,如果不满足结束循环的条件,则将文件 cursor position 设置回循环的开头:

void Interpreter::end_loop() {
    // If the cell's value is 0, we can end the loop
    if(this->char_array[this->char_ptr] == 0) {
        this->loop_begin_pointer = -1;
    }
    // Otherwise, go back to the beginning of the loop
    if(this->loop_begin_pointer > -1){
        this->file.seekg(this->loop_begin_pointer, std::ios::beg);
        this->line = this->loop_begin_line;
        this->column = this->loop_begin_col;
    }
}

我能够输入调试信息,并且可以显示堆栈跟踪以进一步明确问题。

带有一行循环的堆栈跟踪( ++[->+<] ):

+ + [ - > + < ] [ - > + < ] done.

这按预期工作。

多行循环:

++[
-
>
+<]

堆栈跟踪:

+ + [ - > + < ] > + < ] <- when it looped back, it "skipped" '[' and '-' characters.

由于永远不会满足结束条件,因此永远循环(即第一个单元格的值永远不会为 0,因为它永远不会递减)。

奇怪的是,以下工作:

++[
-
>+<]

它遵循与第一个示例相同的堆栈跟踪。 这个工作和最后一个例子不工作是什么让我很难解决这个问题。

如果需要有关程序应该如何工作或其输出的更多信息,请告诉我。 抱歉,这篇文章太长了,我只想尽可能清楚。

编辑 1: class 具有文件 object 作为std::ifstream file; . 在构造函数中,它使用this->file.open(filename)打开,其中filename作为参数传入。

对于文件 stream, seekg最终是根据 C 标准库中的fseek定义的。 C 标准有这样的说法:

7.21.9.2/4 For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET .

因此,对于以文本模式打开的文件,您无法对偏移量进行任何算术运算。 您可以倒回到开头,最后是 position,或者返回到您之前所在的 position 并使用tellg (最终调用ftell )捕获。 其他任何事情都会表现出未定义的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM