简体   繁体   English

C 程序执行与 shell 不同

[英]C Program executing differently from shell

I am trying to read this input as characters into memory in c in a 2 dimensional array.我正在尝试将此输入作为字符读取到二维数组中的 c 中的内存中。

00P015
00P116
030000
06P0ZZ
030005
06P1ZZ
04P0ZZ
26P1ZZ
3412ZZ
030010
06P0ZZ
99ZZZZ
030010
06P1ZZ
99ZZZZ
ZZ0000
ZZ0010

My code is我的代码是

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int pr;
int value;
/*These are variables representing the VM itself*/

char IR[6] ;
short int PC = 0 ;

int P0 ;                                                                //these are the pointer registers
int P1 ;
int P2 ;
int P3 ;

int R0 ; //GP regs
int R1 ;
int R2 ;
int R3 ;

int ACC ;
char PSW[2];
char memory [100][6]  ;                                                 //this is the program memory for first program
short int opcode ;                                                      //nice to know what we are doing
int program_line = 0 ;


int fp ;
int i ;
int q = -1;                                                                  //Used to iterate through memory to execute program
int TrueFalse;                                                          //True / False value for check statements, 1 implies true, 0 implies false
int halt = 0;
int address;


char input_line [7] ;

main(int argc, char *argv[])
{                                                                       //Read file into VM
    fp = open("C:\\Users\\Whiskey Golf\\ClionProjects\\untitled\\program.txt", O_RDONLY) ;
    printf("Open is %d\n", fp) ;                                        //always check the return value.

    if (fp < 0)                                                         //error in read
    {printf("Could not open file\n");
        exit(0) ;
    }
                                                                        //read in the first line of the program
    int charRead = read (fp, input_line, 8 ) ;                          //returns number of characters read`
    printf("\n*******************************\n");
    printf("* Reading Program Into Memory *\n");
    printf("*******************************\n");
    while (1)
    { if (charRead <= 0)                                                //indicates end of file or error
            break ;                                                     //breaks out of infinite loop

        for (i = 0; i < 6 ; i++)                                        //If we get here must have correctly read in a line of program code.
            memory[program_line][i] = input_line[i] ;                   //copy from input line into program memory

        printf("Program Line %d: ", program_line) ;                     //printing out program line for debugging purposes
        for(i = 0; i <  6; i++)
            printf("%c", memory[program_line][i]) ;
        printf("\n") ;

        opcode = (memory[program_line][0] -48) *10 ;                    //Get opcode, print out opcode to console
        opcode += (memory[program_line][1] -48) ;

        printf("Opcode is %d\n", opcode) ;

        charRead = read (fp, input_line, 8) ;                           //read in next line of code

        if(input_line[0] == 'Z')                                        //if the firat character is a 'Z' then you are reading data.
            break ;                                                     //No more program code so break out of loop

        program_line++ ;                                                //now at a new line in the prog
        printf("%n");
    }

The issue I am having is that when I run the program in the IDE I wrote it in, Clion, my output is correct, I get我遇到的问题是,当我在我编写的 IDE 中运行程序时,Clion,我的输出是正确的,我得到

Program Line 0: 00P015
Opcode is 0
Program Line 1: 00P116
Opcode is 0
Program Line 2: 030000
Opcode is 3
Program Line 3: 06P0ZZ
Opcode is 6

But when I run the code via a shell via gcc compilation then ./a.out execution, the output I get is但是当我通过 gcc 编译通过 shell 运行代码然后 ./a.out 执行时,我得到的输出是

Program Line 0: 00P015
Opcode is 0
Program Line 1: 16
Opcode is -528
Program Line 2: 00
Opcode is -528
Program Line 3: ZZ
Opcode is-528

I have been trying to debug this issue for a while now, and I can not get it to work correctly when I do it through the shell, which is the way I need to do it.我已经尝试调试这个问题一段时间了,但是当我通过 shell 进行调试时,我无法让它正常工作,这是我需要的方式。 Any help would be greatly appreciated.任何帮助将不胜感激。

You are reading 8 bytes which takes the end of line character '\\n' and tries to store it in a 7 bytes array.您正在读取8个字节,它采用行尾字符'\\n'并尝试将其存储在7个字节的数组中。

read (fp, input_line, 8)

this leads to undefined behavrio, and it should be这会导致未定义的行为,应该是

read(fp, input_line, 7)

And then you could just discard the next byte like然后你可以丢弃下一个字节

char discard; 
read(fp, &discard, 1);

I suppose you was reading 8 bytes to consume the end of line character, so you could have increased the array size to 8 and ignore the last character or simply read it and discard it.我想您正在读取8个字节来消耗行尾字符,因此您可以将数组大小增加到8并忽略最后一个字符,或者只是读取它并丢弃它。

EDIT : Looking closely at the data and your code, I found out that I don't understand what you try to do, you must read just 7 characters, that will include the trailing '\\n' , the following code will work if and only if there is always a new line '\\n' after each line, otherwise it will skip the last line, you should think of the obvious solution yourself.编辑:仔细查看数据和您的代码,我发现我不明白您尝试做什么,您必须只读取7字符,其中将包括尾随'\\n' ,如果和,以下代码将起作用只有在每行后面总是有一个新行'\\n' ,否则会跳过最后一行,你应该自己考虑明显的解决方案。 Also, see this comment , if you write the program with a text editor on MS Windows, you will have trouble.另外,请参阅此评论,如果您在 MS Windows 上使用文本编辑器编写程序,则会遇到麻烦。 To solve that you can just use fopen() instead of low level I/O.要解决这个问题,您可以使用fopen()而不是低级 I/O。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int
main(void)
{
    int file;
    ssize_t length;
    char buffer[7];
    file = open("program.txt", O_RDONLY);
    if (file == -1)
        return -1;
    while ((length = read(file, buffer, sizeof(buffer))) == 0)
    {
        int opcode;
        /* You will need to overwrite the '\n' for the printf() to work 
         * but you can skip this if you don't want to print the command
         */
        buffer[length - 1] = '\0'; 
        opcode = 10 * (buffer[0] - '0') + buffer[1] - '0';
        fprintf(stderr, "Command: `%s'\n\topcode: %d\n", buffer, opcode);
    }
    close(file);
    return 0;
}
char input_line [7] ;

int charRead = read (fp, input_line, 8 ) ;

Reads 8 bytes into a 7 byte array, which is bad.将 8 个字节读入 7 个字节的数组,这是错误的。 It just wrote over some memory after the array, but since the array is 7 bytes and most data is aligned on 4 or 8 byte values, you probably get away with it by not reading data over anything important.它只是在数组之后写入了一些内存,但是由于数组是 7 个字节,并且大多数数据都在 4 或 8 字节值上对齐,因此您可能不会通过读取任何重要的数据而逃脱它。

But!!!但!!! Here is your data:这是您的数据:

00P015<EOL>
00P116<EOL>
030000<EOL>
06P0ZZ<EOL>
030005<EOL>
...

On a Unix-based system where the end of line is one byte, reading 8 bytes will read在行尾为 1 个字节的基于 Unix 的系统上,读取 8 个字节将读取

00P015<EOL>0

And the next eight bytes will read接下来的八个字节将读取

0P116<EOL>03

etcetera... So here is your data on drugs:等等......所以这是你的药物数据:

00P015<EOL>0
0P116<EOL>03
0000<EOL>06P
0ZZ<EOL>0300
05<EOL>...

See what happens?走着瞧吧? Not what you need or want.不是您需要或想要的。

How this could work in the IDE, smurfed if I know, unless the input file is actually a windows text file (two byte end of line mark), but it's playing with fire.这如何在 IDE 中工作,如果我知道,除非输入文件实际上是一个 Windows 文本文件(行尾标记的两个字节),但它正在玩火。 I'm going to stick with C and pitch fscanf as an alternative to read.我将坚持使用 C 并将fscanf作为阅读的替代方案。 I also stripped out all of the stuff not essential to this example.我还去掉了所有对这个例子不重要的东西。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>


int main(int argc, char *argv[])
{
    (void) argc; // I'm being pedantic. As pointed out below in the comments, this
                 // is not needed. Main needs no arguments. I just like them.
    (void) argv;
    //Read file into VM
// moved all variables into function
    char memory [100][6] ; //This is likely program death if you read more than 100 
                           // lines from the file. There are no guards to prevent this 
                           // in the original code.
    int opcode ;
    int program_line = 0 ;


    FILE* fp ; //using a C FILE handle rather than a posix handle for maximum portability

    char input_line [8] ;// death if a line is poorly formatted and has extra characters, 
                         // but in this case, the whole program falls apart.                            
                         // Went with 8 in case the input file was formatted for Windows.

    fp = fopen("asd.txt", "r") ; // using c standard library file open
    if (fp == NULL)
    {
        printf("Could not open file\n");
        return 0 ;
    }
    int itemsRead = fscanf(fp, "%s\n", input_line) ;
    //fscanf is a much more tractable reader. This will read one string of characters 
    // up to the end of line. It will easily and happily run past the end of input_line 
    // if the line is poorly formatted
    // handles a variety of EOL types. and returns the number of the requested 
    // items read. In this case, one item.
    printf("\n*******************************\n");
    printf("* Reading Program Into Memory *\n");
    printf("*******************************\n");
    while (itemsRead == 1 && input_line[0] != 'Z' && program_line < 100) 
    { // much better place for the exit conditions. Also added test to prevent 
      // overrunning memory
        for (int i = 0; i < 6 ; i++)
        {
            memory[program_line][i] = input_line[i] ;
        } // this can also be performed with memcpy
        printf("Program Line %d: ", program_line) ;
        for(int i = 0; i <  6; i++)
        {
            printf("%c", memory[program_line][i]) ;
        } // if we were using properly terminated c-style strings, and we are not, 
          // this loop and the following printf("\n") could be replaced with  
          // printf("%s\n", memory[program_line]). As it is putc would be a more 
          // efficient option
        printf("\n") ;

        opcode = (memory[program_line][0] -'0') *10 ;  // '0' much easier to read than 48
        opcode += memory[program_line][1] -'0' ;

        printf("Opcode is %d\n", opcode) ;

        charRead = fscanf(fp, "%s\n", input_line) ;

        program_line++ ;
        printf("\n"); // fixed typo
    }
}

And in C++, this sucker is trivial而在 C++ 中,这个傻瓜是微不足道的

#include <iostream>
#include <fstream>
#include <vector>

int main(int argc, char *argv[])
{
    (void) argc; // I'm still being pedantic.
    (void) argv;
    //Read file into VM

    std::vector<std::string> memory;
    int opcode;

    std::ifstream in("asd.txt");
    std::cout << "\n*******************************\n"
              << "* Reading Program Into Memory *\n"
              << "*******************************\n";
    std::string input_line;
    while (std::getline(in, input_line) && input_line[0] != 'Z')
    {
        memory.push_back(input_line);
        std::cout << input_line << std::endl;
        opcode = (input_line[0] - '0') * 10 + input_line[1] - '0';

        std::cout << "Opcode is " << opcode << std::endl << std::endl;
    }
}

A note on being pedantic.关于迂腐的注意事项。 There is this wonderful compiler option called -pedantic It instructs the compiler to do some fairly anally retentive error checking.有一个很棒的编译器选项,叫做-pedantic它指示编译器做一些相当保留的错误检查。 Add it , -Wall , and -Wextra to your command line.将它、 -Wall-Wextra添加到您的命令行中。 Together they will spot a lot of mistakes.他们一起会发现很多错误。 And some stuff that isn't mistakes, but you can't win them all.还有一些不是错误的东西,但你无法赢得它们。

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

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