RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 884534
Accepted
golubtsoff
golubtsoff
Asked:2020-09-23 19:53:08 +0000 UTC2020-09-23 19:53:08 +0000 UTC 2020-09-23 19:53:08 +0000 UTC

如何避免 C 中的代码重复

  • 772

假设我们有以下数据结构:

enum Color{
    Red,
    Blue,
    Black,
    White
};

struct Car{
    char* model;
    enum Color color;
    double engineCapacity;
};

struct Cars{
    struct Car *garage;
    size_t count;
};

有两个函数可以在类型列表中查找具有匹配字段的元素color:engineCapacityCars

struct Car *findByColor(struct Cars cars, enum Color color){
    while(cars.count-- > 0){
        if (cars.garage->color == color){
            return cars.garage;
        }
        cars.garage++;
    }
    return NULL;
}

struct Car *findByEngineCapacity(struct Cars cars, double engineCapacity){
    while(cars.count-- > 0){
        if (cars.garage->engineCapacity == engineCapacity){
            return cars.garage;
        }
        cars.garage++;
    }
    return NULL;
}

可以看出,功能几乎是相互重复的。你能告诉我在这种情况下如何避免代码重复吗?

c
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    user7860670
    2020-09-23T20:59:27Z2020-09-23T20:59:27Z

    我们实现了一个类似于算法的自行车::std::find_if:

    typedef struct Car t_Car;
    typedef struct Cars t_Cars;
    typedef int t_Bool;
    typedef uintptr_t t_Context;
    typedef t_Bool ( * t_Predicate )(t_Context const context, t_Car const * const p_car);
    
    t_Car *
    FindCar_If(t_Cars * const p_cars, t_Predicate const p_predicate, t_Context const context)
    {
        t_Car * p_found_car = NULL;
        size_t car_index = 0;
        assert(p_cars);
        assert(p_cars->garage);
        assert(p_predicate);
        while(p_cars->count != car_index)
        {
            t_Car * const p_car = p_cars->garage + car_index;
            if((*p_predicate)(context, p_car))
            {
                p_found_car = p_car;
                break;
            }
            ++car_index;
        }
        return p_found_car;
    }
    
    t_Bool
    Match_Colour(t_Context const context, t_Car const * const p_car)
    {
        assert(p_car);
        return p_car->colour == ((enum Colour) context);
    }
    
    t_Bool
    Match_EngineCapacity(t_Context const context, t_Car const * const p_car)
    {
        assert(p_car);
        return p_car->engineCapacity == *((double const *) context);
    }
    
    // Пример использования:
    t_Cars cars;
    // добавляем машины...
    {
        enum Colour const colour = Red;
        t_Car * p_red_car = FindCar_If(&cars, &Match_Colour, (t_Context) colour);
    }
    {
        double const capacity = 0.5;
        t_Car * p_hp_car = FindCar_If(&cars, &Match_EngineCapacity, (t_Context) &capacity);
    }
    
    • 2
  2. avp
    2020-09-24T02:36:03Z2020-09-24T02:36:03Z

    保持与手动编码搜索功能的每个变体相同的效率的一种方法是使用宏。

    您将需要几个宏来实现您的程序。一个用于生成函数的名称和代码,另一个用于表示搜索参数与结构字段的比较Car(如果您只管理运算符==以合适方式工作的字段,则可以省略) .

    如果您打算将搜索函数的代码放在一个单独的文件中,您还需要一个生成函数原型的宏。

    使用字段名称和搜索参数类型调用代码生成宏将为该特定字段生成搜索代码(这类似于在 C++ 中使用模板)。

    以这种方式创建的函数的调用方式与在问题文本中的调用方式相同,即 具有与字段类型相对应的搜索参数。

    这是 3 个文件的示例(为了显示一般情况)。

    头文件定义数据结构和宏:

    #ifndef _CARS_H
    #define _CARS_H
    
    enum Color{
        Red,
        Blue,
        Black,
        White
    };
    
    struct Car{
        char* model;
        enum Color color;
        double engineCapacity;
    };
    
    struct Cars{
        struct Car *garage;
        size_t count;
    };
    
    // Макрос делает функцию с суффиксом в ее имени из названия поля поиска
    #define MAKE_FINDCAR_FUNC(field, T) struct Car *findBy_ ## field (struct Cars cars, T value) FIND_BODY_CODE(field)
    // Макрос для прототипа такой функции
    #define DCL_FINDCAR_FUNC(field, T) extern struct Car *findBy_ ## field (struct Cars cars, T value)
    
     // выражение по умолчанию для сравнения поля с аргументом функции
     #ifndef CMPEX
     #define CMPEX(FIELD_NAME) (cars.garage->FIELD_NAME == value)
     #endif
    
     // тело функции
     #define FIND_BODY_CODE(FIELD_NAME) { \
         while(cars.count-- > 0){ \
           if (CMPEX(FIELD_NAME)) return cars.garage; \
           cars.garage++;\
         } \
         return 0; \
     }
    
     #endif
    

    这是具有按型号名称查找汽车的功能的文件可能看起来的样子

     #include <stdlib.h>
    
     #include "cars.h"
     #include <string.h>
    
     // используем strcmp() для поиска модели по ее названию, поэтому включаем <strings.h>
     #undef CMPEX
     #define CMPEX(x) (strcmp(cars.garage->model, value) == 0)
    
     // получим код с именем findBy_model
     MAKE_FINDCAR_FUNC(model, char *)
    
     // да, это все что нужно написать для создания новой функции
    

    现在具有 main() 和按颜色和 engineCapacity 搜索功能的文件

     #include <stdio.h>
     #include <stdlib.h>
    
     #include "cars.h"
    
     /*
       делаем функцию
       struct Car *findBy_engineCapacity(struct Cars cars, double value) { ... }
     */
     MAKE_FINDCAR_FUNC(engineCapacity, double)
     /*
       делаем функцию
       struct Car *findBy_color(struct Cars cars, enum Coler value) { ... }
     */
     MAKE_FINDCAR_FUNC(color, enum Color)
     /*
       делаем прототип
       extern  struct Car *findBy_model(struct Cars cars, enum Coler value)
     */
     DCL_FINDCAR_FUNC(model, char *);
    
     int main() {
         struct Car car1 = {"ford", Red, 2.5};
         struct Car car2 = {"reno", Black, 1.8};
         struct Cars cars;
         cars.count = 2;
         cars.garage = (struct Car*) malloc(sizeof(struct Car) * cars.count);
         *cars.garage = car1;
         *(cars.garage + 1) = car2;
    
         struct Car *car3 = findBy_engineCapacity(cars, 2.5);
         if (car3)
           puts(car3->model);
    
         enum Color color = Black;
         struct Car *car4 = findBy_color(cars, color);
         if (car4)
           puts(car4->model);
    
         struct Car *p = findBy_model(cars, "reno");
         if (p)
           puts(p->model);
    
         free(cars.garage);
         return 0;
     }
    

    如果您有任何问题,请随时在评论中提问。

    • 1
  3. golubtsoff
    2020-09-23T22:21:45Z2020-09-23T22:21:45Z

    谢谢@VTT,有点想通了。

    #include <stdio.h>
    #include <stdlib.h>
    
    enum Color{
        Red,
        Blue,
        Black,
        White
    };
    
    struct Car{
        char* model;
        enum Color color;
        double engineCapacity;
    };
    
    struct Cars{
        struct Car *garage;
        size_t count;
    };
    
    int equalColor(struct Car *car, uintptr_t color){
        return car->color == (enum Color) color;
    }
    
    int equalEngineCapacity(struct Car *car, uintptr_t engineCapacity){
        return car->engineCapacity == *((double *)engineCapacity);
    }
    
    struct Car *findByField(struct Cars cars, int (*equal)(struct Car *, uintptr_t), uintptr_t value){
        while(cars.count-- > 0){
            if ((*equal)(cars.garage, value)){
                return cars.garage;
            }
            cars.garage++;
        }
        return NULL;
    }
    
    int main() {
        struct Car car1 = {"ford", Red, 2.5};
        struct Car car2 = {"reno", Black, 1.8};
        struct Cars cars;
        cars.count = 2;
        cars.garage = (struct Car*) malloc(sizeof(struct Car) * cars.count);
        *cars.garage = car1;
        *(cars.garage + 1) = car2;
    
        double engineCapacity = 2.5;
        struct Car *car3 = findByField(cars, &equalEngineCapacity, (uintptr_t) &engineCapacity);
    
        enum Color color = Black;
        struct Car *car4 = findByField(cars, &equalColor, (uintptr_t) color);
    
        free(cars.garage);
        return 0;
    }
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5