It is often said that the art of computer programming is partly dealing with complexity and partly naming something. In addition, I think “sometimes you need to add drawings” is largely correct.
In this article, I will write a small C program, name something, and deal with some complexity.
Excellent UNIX Programming Philosophy
First of all, you should know that this C program is a Unix Command line tools.
This means that it runs on (or can be ported to) operating systems that provide UNIX C running environment. When Bell Labs invented UNIX, it was full of design philosophy from the beginning.
In my own words: the program only does one thing, does it well, and does some operations on the file. Although “do one thing and do it well” makes sense, the “do something with the file” section seems a little inappropriate.
Facts have proved that the abstract “file” in UNIX is very powerful.
A UNIX file is a byte stream that ends with the end of file (EOF) flag, that’s all.
Any other structure in the file is imposed by the application, not the operating system.
The operating system provides system calls that enable programs to perform a standard set of operations on files: open, read, write, address, and close (among others, but that’s complicated).
Standardized access to files allows different programs to share the same abstraction and work together, even if they are programs written by different people in different languages.
Having a shared file interface makes it easy to buildComposableThe program becomes possible.
The output of one program can be used as the input of another program.
The operating system of UNIX family provides three files by default when executing programs: standard input (stdin), standard output (stdout) and standard error (stderr).
Two of these files are write only: stdout and stderr。 and Stdin is read-only. When we use file redirection in common shells such as bash, we can see its effect.
$ ls | grep foo | sed -e ‘s/bar/baz/g’ > ack
This instruction can be briefly described as: LS The result of is written to the standard output, which redirects to grep Standard input, grep Redirect standard output to sed Standard input for, sed Redirect the standard output of to the current directory with the file name ACK file.
We want our program to work well in this flexible and excellent ecosystem, so let’s write a program that can read and write files.
Meow meow: stream encoder / decoder concept
When I was a child with open teeth, I learned a lot of coding schemes when I learned computer science.
Some of them are used to compress files, some are used to package files, and others are useless and therefore very stupid.
In order to make our program useful, I updated one for it 21st century And implements the concept of a coding scheme called “meow meow”.
The basic idea here is to get the file and encode each half byte (half byte) with the text “meow”. Lowercase letters represent 0 and uppercase letters represent 1.
Because it will replace 4 bits with 32 bits, it will expand the size of the file. Yes, it makes no sense. But when you see this code, you will be surprised.
$ cat /home/your_sibling/.super_secret_journal_of_my_innermost_thoughts
The complete source code can be found in GitHub I found it up there.
Now that I have determined to write a program to encode and decode files in “meow meow” format, I execute the following command in the shell:
$ mkdir meowmeow
$ cd meowmeow
$ git init
$ touch Makefile # Method of compiling program
$ touch main.c # Processing command line options
$ touch main.h # Global constants and definitions
$ touch mmencode.c # Realize the coding of meow meow file
$ touch mmencode.h # Description encoding API
$ touch mmdecode.c # Realize the decoding of meow meow file
$ touch mmdecode.h # Description decoding API
$ touch table.h # Define encoding lookup table
$ touch .gitignore # The file name in this file will be ignored by GIT
$ git add .
$ git commit -m “initial commit of empty files”
Simply put, I created a directory full of empty files and submitted it to GIT.
Even if there is no content in these files, you can still infer the purpose of each file from its file name. In case you don’t understand, I’m here touch The command is briefly described later.
Usually, the program starts from a simple main.c At the beginning of the file, there are only two or three problem-solving functions.
Then the programmer rashly showed the program to his friend or boss, and then the number of functions in the file quickly exploded in order to support all new “functions” and “requirements”.
The first rule of “program club” is not to talk about “program club”. The second rule is to minimize the functions in a single file.
But what is makefile?
I know the next blockbuster app is for you good kids “Ultimate code breaker 3000” It is written in the integrated development environment, and the construction project is mixed with a series of complex keys such as ctrl-meta-shift-alt-super-b.
But now, using Makefile Files can help do a lot of useful work when building C programs.
Makefile Is a text file that contains how files are handled, and programmers can use it to automatically build binaries (and other things) from source code
Take the following little thing as an example:
00 # Makefile
01 TARGET= my_sweet_program
02 $(TARGET): main.c
03 cc -o my_sweet_program main.c
# Symbol The following text is a comment, such as line 00.
Line 01 is a variable assignment, which will TARGET The variable is assigned to a string my_ sweet_ program。 According to the Convention and my habit, all Makefile Variables are capitalized and words are separated by underscores.
Line 02 contains the file name to be created by recipe in this step and the file it depends on. In this case, the build target is my_ sweet_ Program, which depends on main.c。
The last 03 lines use a tab instead of four spaces. This is the command that will execute to create the target. In this case, we use C compiler front end cc Compile link as my_ sweet_ program。
use Makefile It’s very simple.
cc -o my_sweet_program main.c
Makefile main.c my_sweet_program
Build our meow meow encoder / decoder Makefile It is more complex than the above example, but its basic structure is the same. I’ll break it down into Barney style in another article.
Form is accompanied by function
My idea is that the program reads it from one file, converts it, and stores the converted results in another file.
The following is what I imagine when I interact with the program command line:
$ meow < clear.txt > clear.meow
$ unmeow < clear.meow > meow.tx
$ diff clear.txt meow.tx
We need to write code for command line parsing and processing input / output streams. We need a function stream to encode and write the results to another stream.
Finally, we need a function to decode the stream and write the result to another stream.
But in the above example, I called two instructions: meow and unmeow？
I know you might think it will lead to more and more complexity.
Minor content: argv  and LN instructions
Recall that the structure of the C language main function is as follows:
int main(int argc, char *argv)
among argc Is the number of command line arguments, argv Is a list of character pointers (strings), argv  Is the path to the file containing the program being executed.
In UNIX system, many programs with complementary functions (such as compression and decompression) look like two commands, but in fact, they are a program with two names in the file system. This technique is achieved by using ln Command creates a file system link to implement the of two names.
In my laptop / usr/bin An example is as follows:
$ ls -li /usr/bin/git*
3376 -rwxr-xr-x. 113 root root 1.5M Aug 30 2018 /usr/bin/git
3376 -rwxr-xr-x. 113 root root 1.5M Aug 30 2018 /usr/bin/git-receive-pack
here git and git-receive-pack Is the same file but has different names.
We say they are the same files because they have the same inode value (first column).
Inode is a feature of UNIX file system, and its introduction goes beyond the scope of this article.
First, we write a program based on its argv We then make sure to create a link for the name that causes the behavior.
In our Makefile Middle, unmeow Links are created in the following ways:
$(LN) -f $< [email protected]
I tend to Makefile Parameterize everything, rarely using “bare” strings.
I put all the definitions in Makefile The top of the file so that you can easily find and change them. When you try to migrate the program to a new platform, you need to cc Change to a cc This will be convenient.
Except for two built-in variables [email protected] and $
The first is a shortcut to the target of this step, in this case $ I can remember this because @ The symbol looks like a target).
Things will certainly become complicated, but it is still under management.
Finally, whether you are changing careers, beginners or advanced, if you want to learn programming~
[noteworthy] myC / C + + programming learning exchange club![Click to enter]
Q & A, learning and communication, technical discussion, and a great collection of programming resources. Zero basic videos are also great~