C language wheel manufacturing (1) - starting style

For some people, the greater the amount of information they are exposed to, the easier it is to get lost. First, they come into contact with a wider world and learn about the diversity and splendor of the world. The second is that after seeing through their limited energy, they are not interested in anything. They are always looking for the "optimal solution" to avoid the sinking of time costs. They will hope to ask questions on Zhihu, and let the people who come here give them one. The optimal path, such as "how to learn C language".

I think drinking coffee is similar to programming. Of course, as a senior poor guy, I don’t have the money to conduct in-depth research on coffee. I just use coffee as an analogy from the limited experience that I often pretend to write code in a Starbucks near the Science Park to see if I can fool investors or like-minded people. For most people in the class, the first language they come into contact with is the C language, then C/C++->Java->python/php/scala/lua, etc., just like when we started drinking American style, bitter, sour, Later, I discovered the New World after adding a little condensed milk, so I tried a latte. Try a cappuccino, and try adding anything to your coffee that can make the bitterness go away or even make it sweeter. As the saying goes, drink alcohol to relieve anxiety and worry, and drink sweets to make coffee not coffee. Finally, one day I realized that I hadn’t had pure coffee for a long time. After drinking a cup of Americano, I realized that this is the taste of coffee.

I feel the same way about the C language itself. Although it has a simple syntax, simple to simple, and simple to not have much infrastructure, every time I get out of the swamp of other languages ​​and return to the embrace of the C language, I always have new insights. Many people maintain an attitude of awe towards c and keep them at a distance, always worrying about whether the code they write will be too naive, too low, or not cool enough to be delayed. This is very unnecessary. Using the article as an analogy, the articles written by masters are not necessarily gorgeous in their words and sentences, but the author's unique insights and ideas are fascinating, just like Han Han's works. And many online articles, even with gorgeous diction, breathless long and short sentences, and breathless comparisons, still cannot save the poor plot and empty imagination, but give people a very embarrassing and artificial feeling. Like large Java CRUD projects - over-engineering, over-encapsulation, polymorphism, design patterns, burj-high inheritance trees, and monsters piled up with 500-pound configuration files.

As the saying goes, a journey of a thousand miles begins with a single step, and a journey of a thousand miles begins with a wheel. Many people still feel unable to write even after they have learned the basic grammar of C. Book knowledge will eventually be converted into engineering practice, and engineering code is not the same as pure academic algorithm code. For example, you may write a sorting algorithm. Bubbling, heap row, quick row slip and fly, but always lined up against a pile of int arrays? The scenarios faced by engineering are not the same. You must pay more attention to how data is stored, how to query, and how to make a wheel that is scalable and implementable and hides the implementation details. The wheel is for other programmers, and it is written with a sense of service. code, this is a detail that pure book code does not pay much attention to, and it is also a good way to convert old school code into engineering usable.

If you have been learning the C language for a period of time and still have a feeling of powerlessness that you can't write, then you might as well start by building wheels. The starting style of building a wheel is the "wallbreaker" of this sense of powerlessness.

First of all, I recommend the Linux platform. If you have not installed Linux, please pay attention to another column of my bow and arrow maintenance guide.

Officially entering the development stage, the most troublesome problem is to name your own project. It must be a horrible thing that makes your legs soft when you hear it. So I decided to start with "grandma's turner aka GT" as the project name. First create a directory, and then create two directories under the root directory of the project to store our header files and source directory. Then let's try to build a simple wheel first - a stack.



// gttypes.h
// Created by Rowland@Sjet on 2018/1/28.
//

#ifndef GTLIB_GTTYPES_H
#define GTLIB_GTTYPES_H

#ifdef __cplusplus
extern "C" {
#endif

#define GT_API            extern
#define GT_OK             (0)
#define GT_ERROR_OUTMEM   (-1)
#define GT_ERROR_FULL     (-2)
#define GT_ERROR_EMPTY    (-3)


#ifdef __cplusplus
}
#endif

#endif

If you want to talk about the starting style of constructing the wheel, this skeleton is it. The outermost macro ifndef define endif is used to tell the compiler not to include me repeatedly, the extern c {} level inside is to inform the C++ compiler to deal with me in the way of c, and the inner layer is our code. Macros should be as intuitive as possible for readability.
// gtstack.h
// Created by Rowland@Sjet on 2018/1/28.
//

#ifndef GTLIB_GTSTACK_H
#define GTLIB_GTSTACK_H
#ifdef __cplusplus
extern "C" {
#endif

#include "gttypes.h"
typedef struct GtStack GtStack;

GT_API GtStack* gt_stack_create(size_t);
GT_API int gt_stack_push(GtStack*, void*);
GT_API int gt_stack_pop(GtStack*, void**);
GT_API void gt_stack_destroy(GtStack**);

#ifdef __cplusplus
}
#endif
#endif //


If not necessary, only expose the API in the header file, and try not to expose any specific functions, variables and structures related to the implementation in the header file. In the future, if you want to close the source, the implementation will only provide the so library, and the operation flexibility will be more.

// gtstack.c
// Created by Rowland@Sjet on 2018/1/28.
//

#include <stdlib.h>
#include "../include/gtstack.h"
struct GtStack{
    size_t max;
    int index;
    void** elems;
};

GtStack* gt_stack_create(size_t max){
    GtStack* out = (GtStack*)malloc(sizeof(GtStack));
    if(!out) exit(GT_ERROR_OUTMEM);

    if(max<=0) max = 16;
    out->elems = (void**)calloc(max, sizeof(void*));
    if(!out->elems) exit(GT_ERROR_OUTMEM);

    out->max = max; out->index = 0;
    return out;
}

int gt_stack_push(GtStack* in, void* data){
    if(in->index>=in->max) return GT_ERROR_FULL;

    in->elems[in->index++] = data;
    return GT_OK;
}

int gt_stack_pop(GtStack* in, void** data){
    if(in->index<=0) return GT_ERROR_EMPTY;

    *data = in->elems[--in->index];
    return GT_OK;
}

void gt_stack_destroy(GtStack** in){
    if(*in){
        GtStack* stack = *in;
        free(stack->elems);
        free(stack);
        *in = NULL;
    }
}

The code I wrote is more casual, without scrutiny, but I will not write "declare first, then use" code, it must be done in one step, if you have a modern compiler, it is best not to write something like int a; a=5 ;This kind of code that is declared first and then initialized, most of the code written in this way is to be compatible with old compilers or to maintain a project with a heavy historical burden. In actual projects, dirty reads may occur.

Next, write a main.c in the project root directory to test it
// main.c
// Created by Rowland@Sjet on 2018/1/28.
//
#include <stdio.h>
#include <stdlib.h>
#include "include/gtstack.h"

int main(){
    GtStack* stack = gt_stack_create(10);
    gt_stack_push(stack, "SF");
    gt_stack_push(stack, "韵达");
    gt_stack_push(stack, "申通");
    gt_stack_push(stack, "Yuantong");
    char* p;
    int err;
    while((err=gt_stack_pop(stack, (void**)&p))==GT_OK){
        printf("pop:%s\n", p);
    }
    gt_stack_destroy(&stack);
    return EXIT_SUCCESS;
}

compile, execute
Sjet/> clang main.c include/gtstack.h src/gtstack.c
Sjet/> ./a.out
pop: Yuantong
pop: Shentong
pop: rhyme
pop:SF Express
Sjet/> _

After the verification is passed, the main.c can be deleted, so that the first wheel is built. In the following pages, we will introduce how to use automatic build tools, how to test, how to detect memory leaks, and then introduce several common data structures and algorithms, and then we can create an actual project. Try not to use open source libraries and manually implement the various corners you need. If you are interested, please like and follow!
Code address for this issue: nikoloss

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326116977&siteId=291194637