linux系统编程-一个demo

本目展示一个linux环境下系统编程的一个demo。主要是为了讲解项目下文件夹的布局以及makefile的写法。
程序的源代码来自于书籍《Accelerated c++》一书当中第四章的例子。

布局

一个基本的项目主要是以下5项构成:

  • src:存放项目的源文件。目录可以细分。
  • inc:存放项目的头文件。目录可以细分;
  • bin:存放二进制可执行文件。
  • Makefile:Makefile文件
  • run.sh:运行脚本,命令行参数通过这个脚本传递。

源码

// 路径:./src/main.cpp
#include <vector>
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <ios>
#include <iomanip>
#include <string>
#include <algorithm>
#include "Student/StudentInfo.h"
#include "grade/grade.h"

int main( int argc, char* argv[] ) {

    if( argc != 2 ) {
        std::cerr << "Usage: argv[1] is input path." << std::endl;
        return -1;
    }

    std::vector<StudentInfo> vec_stu;

    std::ifstream fin;
    fin.open( argv[1] );
    if( !fin.is_open() ) {
        std::cerr << "Can not open the file!" << std::endl;
        return -1;
    }

    int maxlen = -1;
    StudentInfo s;
    while( read_stu( fin, s ) ) {
        vec_stu.push_back(s);
        int name_sz = s.name.size();
        maxlen = (name_sz > maxlen)?name_sz:maxlen;
    }

    std::sort( vec_stu.begin(), vec_stu.end(), compare );

    try {
        std::streamsize prec = std::cout.precision();
        std::cout << std::setprecision(3);
        int sz = vec_stu.size();
        for( int i = 0; i < sz; ++i ) {
            double total = grade( vec_stu[i].mid, vec_stu[i].fin, vec_stu[i].hw );
            std::string space(maxlen - vec_stu[i].name.size() + 1, ' ');
            std::cout << vec_stu[i].name << space << total << std::endl;
        }
        std::cout << std::setprecision(prec);
    }
    catch( std::domain_error e ) {
        std::cerr << e.what();
        fin.close();
        return -1;
    }

    fin.close();
    return 0;
}
// 路径:./src/median.cpp
#include <vector>
#include <algorithm>
#include <stdexcept>
#include "median/median.h"

double median( std::vector<double> vec ) {
    if( !vec.size() )
        throw std::domain_error( "vec is empty!" );

    std::sort( vec.begin(), vec.end() );

    int sz = vec.size();
    return (sz & 1)?vec[sz/2]:1.0/2*( vec[sz/2] + vec[sz/2-1] );
}
// 路径:./src/grade.cpp
#include "grade/grade.h"
#include "median/median.h"
#include <vector>
#include <stdexcept>

double grade( double mid, double fin, double med ) {
    return mid * 0.2 + fin * 0.4 + med * 0.4;
}

double grade( double mid, double fin, const std::vector<double>& hw ) {
    int sz = hw.size();
    if( !sz ) 
        throw std::domain_error( "Empty hw!" );

    double med = median(hw);
    return grade( mid, fin, med );
}
// 路径:./src/StudentInfo.cpp
#include "Student/StudentInfo.h"

bool compare( const StudentInfo& a, const StudentInfo& b ) {
    return a.name < b.name;
}

std::istream& read_stu( std::istream& is, StudentInfo& s ) {
    if( is ){
        is >> s.name >> s.mid >> s.fin;
        read_stu_hw( is, s.hw );
    }
    return is;
}

std::istream& read_stu_hw( std::istream& is, std::vector<double>& hw ) {
    if( is ) {
        hw.clear();
        double x = 0.0;
        while( is >> x ) {
            hw.push_back(x);
        }
        is.clear();
    }
    return is;
}
// 路径:./inc/median
#ifndef MEDIAN_H_
#define MEDIAN_H_
#include <vector>

double median( std::vector<double> );

#endif
// 路径:./inc/grade/
#ifndef GRADE_H_
#define GRADE_H_
#include <vector>

double grade(double, double, double);
double grade(double, double, const std::vector<double>&);

#endif
// 路径:./inc/StudentInfo
#ifndef STUDENT_INFO_H_
#define STUDENT_INFO_H_
#include <string>
#include <vector>
#include <istream>

struct StudentInfo {
    std::string name;
    double mid;
    double fin;
    std::vector<double> hw;
    StudentInfo() : mid(0.0), fin(0.0) {}
};

bool compare( const StudentInfo&, const StudentInfo& );
std::istream& read_stu( std::istream&, StudentInfo& );
std::istream& read_stu_hw( std::istream&, std::vector<double>& );

#endif
EXE_DIR := ./bin
INC_DIR := ./inc
SRC_DIR := ./src

TARGET := $(EXE_DIR)/main
OBJS := $(wildcard ./src/*.cpp)
CFLAGS := -Wall -g -I$(INC_DIR) -std=c++11

CC := g++

$(TARGET):$(OBJS)
    $(CC) -o $@ $(OBJS) $(CFLAGS)

clean:
    rm -rf $(TARGET)

总结

我觉得需要特别注意的有:

  • 头文件路径的写法。由于makefie文件 -I /inc,只是链接了头文件目录,但是头文件有各自的子目录,所以写include命令的时候需要包含子目录。这也是leveldb的写法。
  • 执行目录不是源文件的目录,这点要注意。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值