c代写 | C语言代写 | 作业assembly | 代做bash | mining | 代写shell | project | 代写lab – Compile, Run, Make C Programs on Linux

Compile, Run, Make C Programs on Linux

c代写 | C语言代写 | 作业assembly | 代做bash | data mining | 代写shell | project | 代写lab – 本题是一个利用C和bash进行练习的代做, 对C和bash的编程流程进行训练解析, 涵盖了assembly/bash/mining/shell等程序代做方面, 这个项目是lab代写的代写题目

express代写 代写express nodejs代做 web代写

Len Hamey Revised 1 3 June 2019 [email protected]

Introduction

This document discusses compiling and running your own C programs on the Linux servers ash.science.mq.edu.au and iceberg.science.mq.edu.au. The commands and concepts should be the same on other Linux environments.

We assume that you have logged into the server with a terminal window such as Putty from Windows or an ssh client on Mac OSX. (See COMP202 from Windows or COMP202 from Mac OSX ). The Computing lab computers are Windows machines, so you should become familiar with Putty.

Concepts

Computers cannot directly execute the programs that we write. The hardware does not understand C, or Java, or even assembly language. The hardware only understands machine instructions. But machine instructions are difficult for humans to understand, so we write our programs in languages that we like, and then use a special program (called a compiler ) to convert our program into machine instructions so that the computer can execute it.

Compilers are quite sophisticated programs. In fact, here at Macquarie University we have a course COMP332 Programming Languages where you learn about the key ideas behind different programming languages and how compilers are written. Modern compilers are capable of not only translating your program into machine code, but also of carefully designing that machine code to make the compiled program run as fast as possible. This is called optimisation.

We will study compilation later in COMP202. For now, the main thing you need to know is that a computer cannot execute C programs, but it can execute a compiled C program. The rest of this document explains how to compile your C program and run it.

Compiling a simple C program

Lets assume that we have a simple C program called hello.c. It contains everybodys first C program: the hello world program. Here is the hello world program.

# include <stdio.h>
int main (int argc, char **argv) {
printf ("Hello, world!\n");
return 0;
}

We wont explain this program here if you need a tutorial introduction to C then please look elsewhere^1. If you want to follow through this document as a brief tutorial, then please create a file hello.c similar to the above by using an editor. The document COMP202 from Windows explains how to edit a file on the Linux servers ash or iceberg, using Notepad++ on a Windows machine.

(^1) There are many tutorials on the Internet; some of them are linked from the Resources section of the COMP202 iLearn web site. Also, the Data File Lab Notes includes a brief explanation of the main function and command line parameters.

To compile this program, we use the GNU C compiler gcc. The command is given below. It is a Unix command, and we have shown the Unix shell prompt as a single $ symbol. You do not type the $ symbol you only type the part that is underlined in this example.

$ gcc o hello hello.c

Analysing this command line, we see the following components.

  1. The command itself is gcc. This is the well known name of the GNU C compiler.
  2. The option o followed by hello specifies the name of the output file as hello. If you wanted to call your program goodday you could specify o goodday instead of
    • o hello, but note that changing the name of the program in this way does not change what it does it still prints Hello, world!
  3. The parameter hello.c is the name of the C program file to be compiled. If appropriate, you can list several C program files and the compiler will compile them all together into one program.

When you run this command, it produces no screen output if it is able to compile the programs. If there is a problem compiling your program, the compiler will display error messages telling you what the problems are. For example, suppose we compile the following program:

int main (int argc char **argv) {
printf ("Hello, world!\n");
return 0;
}

Here is a screen shot where we first use the cat command to display the file hello.c, and then compile it using gcc.

An aside about the prompt. The system prompt shows your logged in user ID,
the short name of the host and the current working directory name. This can
be helpful if you have a few windows open at once, working on different
machines or in different directories.

Here, there is an error at line 1 of the hello.c file. It says that something is missing (perhaps a semicolon, comma or parenthesis) before the word char. Can you see the error in the program listing above?

The comma is missing after argc in the parameters of main. After correcting the typing mistake, we encounter another error.

This time, the compiler is not happy with the way we used printf. What is wrong? The problem isnt that weve written the call to printf badly the problem is that we did not include stdio.h which tells the compiler how to use printf. The corrected code is now:

# include <stdio.h>
int main (int argc, char **argv) {
printf ("Hello, world!\n");
return 0;
}

Compiling now succeeds and we can run the program by typing the command

$ ./hello.

Running a program

After compilation, you run a program by typing its name as a command. In the above example, the program is called hello and it is in the current directory. The name of the current directory is . in Unix, so ./hello is the command that we use to execute our program.

Note. Running our own program and running a Unix system command are
very similar things. To make it clear that we want to run our own program, we
specify the directory where the program can be found. If our program is in the
current directory, we can use the name . for the current directory.
If you type a Unix command that has no directory name, Unix assumes that it is
a system command a goes looking for it in the system directories. The screen
shot below shows what happens if you type the hello command without the
directory name  Unix determines that it does not exist on this system, but
apparently there is a system command called hello that could be installed!
Be careful  omitting the ./ could run a system command that you dont
want to run.

Every Unix command can have parameters, so we can run our program with parameters. However, our simple program ignores the command line parameters, which are passed in the array of strings called argv. The program does the same thing whether we specify command line parameters or not.

We can change our program that it will say hello to the first parameter by checking for the parameter and printing it out. Heres one way to do this:

# include <stdio.h>
int main (int argc, char **argv) {
printf ("Hello, %s!\n", argv[1]);
return 0;
}

In fact, our code is now quite bad because it always assumes that there is a command line parameter provided. Running hello without a parameter now produces strange output.

Going deeper: The notation (null) is what the printf library procedure
produces when it is passed a NULL pointer. The arguments array argv is
terminated by a NULL pointer, so argv[1] is NULL when there is no
parameter specified on the command line. If you see (null) in your
program output when trying to print a string, check for why you might have a
NULL pointer!

We leave it to you (if you wish) to modify the program to check whether argv[1] exists or not and to behave appropriately when it is absent as well as when it is present. Hint: argc is the count of

arguments provided. The count includes argv[0] which is the name of the program itself, so the command ./hello has 1 argument while the command ./hello John has two arguments!

Compiling larger C programs

If a C program fits into one source file then you can compile it as shown above. If it requires two or three source files, you can list them on the command line and the compiler will compile them together into the program. For example:

$ gcc o  project main.c utils.c agents.c

The problem with this approach is that it quickly becomes tiresome to type the whole command every time you want to compile your program.

Fortunately, Unix offers some useful tricks to make life easier for you. In fact, Unix has always featured brevity in its user interface. That is why we list files with ls instead of dir, move them with mv instead of rename and copy them with cp instead of copy Unix users dont want to type any more than they need, whereas MSDOS command line uses longer command names.

Command line editing: The first helpful feature is inside the bash shell: If you press the up-arrow key on your keyboard, it recalls the previous command that you typed. Press it again to recall the command before the previous one. You can scroll back (and forwards) through your command history and select any command to execute again simply press the Enter (or Return) key to execute the selected command. You can also edit the command by using the left and right arrow keys to move through it, and make changes using delete/backspace together with typing new characters into the command.

If recalling previous commands is not helpful enough, you can write a shell script a file of commands that the shell will read and process whenever you type the name of that shell script. Shell scripting is not trivial and not for the faint hearted. There are a couple of important tricks to shell scripting, including the fact that the shell script file has to have execute permission set on it (see man 1 chmod) and the first line has to be #!/bin/bash which informs the system that the file is a bash shell script. On the other hand, shell scripts can do some very powerful things and are regularly used in Unix systems related tasks.

Make

When projects get to be more than a couple of C files, it is really handy to store the commands for compiling and building the project into some sort of script. Make is a scripting language specifically designed for building projects. It allows you not only to specify the commands to be executed but also to indicate when those commands are required. Basically, you tell make that a particular command (such as gcc) needs to be run on a particular set of files if any of those files have been changed. This is called dependencies and it is a central concept of make. Make analyses what has changed and what needs to be brought up to date. It does this by comparing the date-time stamps of the source files with the date-time stamps of the file(s) created by the command(s).

The core idea of make is that your project produces one or more output files, such as compiled executable programs, libraries or other artefacts. Each output is built from some, but not necessarily all of the inputs the source code files and other files that you created by hand. Not only this, but larger projects typically involve creating intermediate files that are produced from one or a few of the inputs and are later combined together to produce the final outputs. Imagine that it takes 30 minutes to compile every program and process every intermediate file in your project to

produce the final output. Wouldnt it be nice if you could make a small change to one of the input files and not have to recompile everything? That is where dependencies are involved.

A make file consists of rules that express dependency relationships between files, and the commands that create/recreate the output file when either the output file is missing or one of the input files has changed. Here is a simple make file for the hello world program discussed earlier. The file is called makefile. The make command always looks for the file with that name.

hello: hello.c
gcc o hello hello.c

The first line of the file says that the output file hello depends on the input file hello.c. (In make terminology, hello is the target and hello.c is the dependency of the rule.) The second line says that to create or recreate hello, make should run the gcc command. The second line commences with a TAB character. This is very important make insists that command lines commence with a TAB character. It will even complain about the syntax of your makefile if the TABs have been converted to spaces! This is inconvenient because you dont want TAB characters in your C programs but you need them in your makefile, so you need to be aware of this when editing C code and make files.

In the following example, we first create the makefile using vi (the editing session does not remain on the screen so it does not appear in the screen capture). When make is run the first time, hello is created. Running make again does not recreate hello because the hello.c file has not changed, so make believes that the current hello program is still up to date, which it is.

Make can do a lot more than compile programs it can also run them and test them. Lets add a rule to test the hello world program.

test: hello
./hello Len > output.txt
diff output.txt expected.txt
hello: hello.c
gcc o hello hello.c

The first line of the new rule says that we want to build the target test which depends on hello. If the hello program is not up to date, make will recompile it before running the commands in this rule. In this particular rule, the target test is a file that is never actually created. This is quite common in make files; such phony targets are useful because every time you try to make them, the corresponding commands will be executed.

The second line of the new rule is a command to execute the compiled hello program with the parameter Len and save the output into the file output.txt^2. The third line uses the Unix diff command^3 to compare output.txt with the expected output that should be in the file expected.txt. Here is what is in expected.txt:

Hello, Len

In the screen shot below, the cat command is used to create the text file expected.txt^4. After typing in the text contents, you need to hold down the Ctrl key and press the d key to indicate the end of your input. Ctrl-D is what Unix uses to represent the end of file on the terminal.

In this example, we use the command

$ make test

to specifically build the target test in our makefile. By default, make will build the first target in the makefile, so if the test rule is placed at the start of the file (as in the example above) we can use the make command without any parameters to achieve the same result. Typically, the first rule in a make file should be the most commonly used operation such as building and testing the project, so it makes sense for the test rule to be first in our makefile.

The make results show that output.txt is not the same as expected.txt. Exa mining the differences, it is evident that there is an exclamation mark at the end of the actual output, but this is missing from expected.txt. To solve this, we should typically modify the program, assuming that the expected output is correct according to the specification.

(^2) If you are unfamiliar with the use of > in this command, read up on I/O redirection in the Unix shell. (^3) See man 1 diff for details about the diff command. (^4) It is usually better to use a text editor to create even the simplest text file, because it is difficult to correct typing errors in cat.