โครงการ C หลีกเลี่ยงความขัดแย้งในการตั้งชื่อ


13

ฉันกำลังดิ้นรนเพื่อหาคำแนะนำในโลกแห่งความเป็นจริงในทางปฏิบัติเกี่ยวกับการตั้งชื่อฟังก์ชั่นสำหรับโครงการห้องสมุดซีขนาดกลาง โครงการห้องสมุดของฉันถูกแยกออกเป็นสองสามโมดูลและ submodules ด้วยส่วนหัวของพวกเขาเองและตามสไตล์ OO (ฟังก์ชั่นทั้งหมดใช้โครงสร้างที่แน่นอนว่าเป็นอาร์กิวเมนต์แรกไม่มี globals ฯลฯ ) มันเป็นสิ่งที่เราชอบ:

MyLib
  - Foo
    - foo.h
    - foo_internal.h
    - some_foo_action.c
    - another_foo_action.c
    - Baz
      - baz.h
      - some_baz_action.c
  - Bar
    - bar.h
    - bar_internal.h
    - some_bar_action.c

โดยทั่วไปฟังก์ชั่นนั้นใหญ่เกินกว่าจะยกตัวอย่างเช่นsome_foo_actionและanother_foo_actionในfoo.cไฟล์การนำไปใช้งานทำให้ฟังก์ชั่นส่วนใหญ่คงที่และเรียกมันว่าวัน

ฉันสามารถจัดการกับการลอกสัญลักษณ์ภายใน ("โมดูลส่วนตัว") เมื่อสร้างห้องสมุดเพื่อหลีกเลี่ยงความขัดแย้งสำหรับผู้ใช้ของฉันด้วยโปรแกรมไคลเอนต์ของพวกเขา แต่คำถามคือวิธีตั้งชื่อสัญลักษณ์ในห้องสมุดของฉัน? จนถึงตอนนี้ฉันได้ทำ:

struct MyLibFoo;
void MyLibFooSomeAction(MyLibFoo *foo, ...);

struct MyLibBar;
void MyLibBarAnAction(MyLibBar *bar, ...);

// Submodule
struct MyLibFooBaz;
void MyLibFooBazAnotherAction(MyLibFooBaz *baz, ...);

แต่ฉันลงท้ายด้วยชื่อสัญลักษณ์ยาวบ้า (นานกว่าตัวอย่าง) ถ้าฉันไม่นำหน้าชื่อด้วย "fake namespace" สัญลักษณ์สัญลักษณ์ภายในของโมดูลจะระบุชื่อการปะทะทั้งหมด

หมายเหตุ: ฉันไม่สนใจเกี่ยวกับ camelcase / Pascal case และอื่น ๆ แค่ชื่อตัวเอง

คำตอบ:


10

การใส่คำนำหน้า (อย่างดี, การผสม) เป็นตัวเลือกเดียวเท่านั้น รูปแบบบางอย่างที่คุณเห็นคือ<library>_<name>(เช่น OpenGL, ObjC runtime) <module/class>_<name>(เช่นส่วนของ Linux), <library>_<module/class>_<name>(เช่น GTK +) แบบแผนของคุณสมเหตุสมผลอย่างสมบูรณ์แบบ

ชื่อยาวไม่จำเป็นต้องแย่ถ้าคาดเดาได้ ความจริงที่ว่าคุณกำลังสิ้นสุดกับบ้าชื่อที่ยาวและฟังก์ชั่นที่มีขนาดใหญ่เกินไปที่จะติดกับฟังก์ชั่นที่เกี่ยวข้องในแฟ้มแหล่งเดียวเพิ่มความกังวลที่แตกต่างกัน คุณมีตัวอย่างที่เป็นรูปธรรมบ้างไหม?


ฉันเห็นว่าคุณมาจากไหน - ฉันสงสัยว่าตัวเองเป็นคนที่คลั่งไคล้เรื่องการแยกไฟล์ออกเป็นส่วนgit mergeๆ หรือเปล่าแต่มันช่วยได้มากในเรื่องการอ่านการบำรุงรักษา เป็นตัวอย่างที่ผมมีโมดูลสำหรับการวาดภาพ UI กับ OpenGL และฉันมีแยกต่างหาก.cไฟล์สำหรับแต่ละองค์ประกอบที่ฉันต้องการ ( slider.c, indicator.cฯลฯ ) การใช้งานองค์ประกอบเหล่านี้มีฟังก์ชั่นการวาดภาพหลักอาจมีความยาวไม่กี่ร้อยบรรทัดและมีจำนวนstaticผู้ช่วยพอสมควร พวกเขายังเรียกฟังก์ชั่นเรขาคณิตบริสุทธิ์เพียงไม่กี่ตัวจากภายในโมดูล UI เสียงนั้นปกติหรือไม่?
Dan Halliday

ตัวอย่างที่ดีของชื่อยาว ๆ อาจเป็นโมดูลเสียงของฉัน - ฉันมีลำดับชั้นAudio Module > Engines > Channels > Filtersที่มีความหมายเช่นMyLibAudioEngines<EngineName>Channel<ActionName>นั้น หรือในตัวกรองของฉัน submodule: MyLibAudioFilters<FilterName><Type><Action>เช่น MyLibAudioFiltersBigSoundingCompressorFloat32Process
Dan Halliday

ไม่มีสิ่งใดที่ดูเหมือนไม่สมเหตุสมผล สองสามร้อยบรรทัดสำหรับฟังก์ชั่นดูเหมือนว่าจะยาวไปหน่อย แต่ถ้าสิ่งที่คุณกำลังวาดมีความซับซ้อนนั่นอาจเป็นเรื่องยากที่จะหลีกเลี่ยง มันหนักหนาสาหัสหรือมีคำสั่งเยอะไหม?
user2313838

Re: ชื่อโมดูลเสียงคุณสามารถย่อ AudioFilters / AudioEngines อย่างที่ฉันคิดว่ามันจะง่ายที่จะบอกว่ามันเป็นตัวกรองหรือโมดูลตามชื่อ ตัวระบุชนิดข้อมูลเช่น Float32 อาจเป็นตัวย่อ (เช่น 'd', 'f') เนื่องจากตัวย่อดังกล่าวเป็นเรื่องธรรมดาในการเขียนโปรแกรม C
user2313838

ขอบคุณสำหรับคำตอบของคุณ - บางครั้งคุณรู้สึกว่าเป็นไปไม่ได้ที่จะได้รับข้อมูลที่ดีเกี่ยวกับสถาปัตยกรรมโปรแกรม C (โดยเฉพาะเมื่อเทียบกับภาษาระดับสูงกว่า) หนังสือ C หลายเล่มที่ฉันอ่านมาแทบจะไม่ได้คิดว่าจะมีโมดูลหลายโมดูลหรือมากกว่าหนึ่งไฟล์! โดยรวมแล้วฉันไม่คิดว่าฉันจะเปลี่ยนแปลงอะไรมากมายยกเว้นการพิจารณาว่าจะใช้ชีวิตกับตัวย่อสำหรับชื่อที่ยาวขึ้น
Dan Halliday

5

การประชุมปกติสำหรับห้องสมุด C คือการใช้ชื่อห้องสมุดเป็นคำนำหน้าสำหรับชื่อที่ใช้งานได้จากภายนอกเช่น

struct MyLibFoo;
void MyLibAFooAction(...);

สำหรับชื่อไลบรารีภายในที่ยังคงสามารถเข้าถึงได้ในหลาย ๆ หน่วยของห้องสมุดไม่มีแบบแผนที่เข้มงวด แต่ฉันจะใช้คำนำหน้าชื่อไลบรารีและการบ่งชี้ว่าเป็นฟังก์ชันภายใน ตัวอย่างเช่น:

struct MyLibInternalFooBaz;
void MyLibInternalFooBazAction();

ฉันยอมรับว่าสิ่งนี้สามารถนำไปสู่ชื่อที่ค่อนข้างยาวและพิมพ์ยาก แต่น่าเสียดายที่เป็นราคาที่เราต้องจ่ายเพราะไม่มีกลไกเช่นเนมสเปซ C ++ เพื่อลดความยาวของชื่อคุณสามารถเลือกใช้ตัวย่อในชื่อของคุณได้โดยเสียค่าใช้จ่าย แต่คุณต้องชั่งน้ำหนักข้อดีและข้อเสียอย่างรอบคอบ


3

หากคุณต้องการหลีกเลี่ยงคำนำหน้ายาวคุณสามารถย่อชื่อไลบรารีเช่นที่ Apple ทำใน iOS และ OS X:

  • NSString เป็นสตริงจากรูท NextStep ของระบบปฏิบัติการ
  • CALayer เป็นเลเยอร์ภาพเคลื่อนไหวหลัก

2

สิ่งที่เกี่ยวกับการมีตัวแปรโครงสร้างทั่วโลก prefilled กับตัวชี้ฟังก์ชั่น?

lib.h

#pragma once

typedef struct
{
    void (*doFoo)(int x);
    const char *(*doBar)(void *p);
} YourApi;

extern const YourApi yourApi;

lib.c:

#include "lib.h"

#include <stdio.h>

static void doFoo(int x)
{
    printf("Doing foo %d\n", x);
}

static const char *doBar(void *p)
{
    printf("Doing bar: %p\n", p);
    return "Hello";
}

const YourApi yourApi = {
    doFoo,
    doBar};

ควบคุมและใช้ประโยชน์:

#include "lib.h"

int main()
{
    yourApi.doFoo(42);
    yourApi.doBar("asd");
}

คำหลักคงที่ จำกัด ขอบเขตของหน่วยการแปลเพื่อที่จะไม่ชนกับผู้อื่น

จากนั้นผู้ใช้สามารถลดได้โดยใช้ตัวชี้ชอบแล้วใช้YourApi *ya = &yourApiya->doFoo(...)

นอกจากนี้ยังเป็นวิธีที่ดีในการจำลองห้องสมุดของคุณสำหรับการทดสอบ


รูปแบบเจ๋ง ๆ มันต้องใช้หม้อไอน้ำเล็กน้อย แต่มันจะทำให้การเติมข้อความอัตโนมัติมีประโยชน์มากขึ้น
Rick Love
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.