Dự án C tránh xung đột đặt tên


12

Tôi đang vật lộn để tìm lời khuyên thực tế trong thực tế về các quy ước đặt tên hàm cho một dự án thư viện C cỡ trung bình. Dự án thư viện của tôi được tách thành một vài mô-đun và mô-đun con với các tiêu đề riêng và theo một cách lỏng lẻo theo kiểu OO (tất cả các hàm đều có cấu trúc nhất định làm đối số đầu tiên, không có toàn cục, v.v.). Nó đặt thứ gì đó như:

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

Nói chung, các hàm quá lớn so với (ví dụ) dính some_foo_actionanother_foo_actiontrong một foo.ctệp thực hiện, làm cho hầu hết các hàm tĩnh và gọi nó là một ngày.

Tôi có thể xử lý tước bỏ các ký hiệu bên trong ("mô-đun riêng tư") khi xây dựng thư viện để tránh xung đột cho người dùng của mình với các chương trình máy khách của họ, nhưng câu hỏi đặt ra là làm thế nào để đặt tên các ký hiệu trong thư viện của tôi? Cho đến nay tôi đã làm:

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

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

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

Nhưng tôi kết thúc với tên biểu tượng dài điên rồ (dài hơn nhiều so với các ví dụ). Nếu tôi không đặt tiền tố tên với "không gian tên giả", tên biểu tượng bên trong của mô-đun sẽ bị xung đột.

Lưu ý: Tôi không quan tâm đến trường hợp lạc đà / trường hợp Pascal, v.v., chỉ tên của chính họ.

Câu trả lời:


10

Tiền tố (tốt, gắn kết) thực sự là lựa chọn duy nhất. Một số mẫu bạn sẽ thấy là <library>_<name>(ví dụ: OpenGL, ObjC runtime), <module/class>_<name>(ví dụ như các phần của Linux), <library>_<module/class>_<name>(ví dụ: GTK +). Đề án của bạn là hoàn toàn hợp lý.

Tên dài không nhất thiết là xấu nếu chúng có thể dự đoán được. Việc bạn kết thúc với các tên và hàm dài điên rồ quá lớn để gắn với các chức năng liên quan trong một tệp nguồn gây ra những lo ngại khác nhau. Bạn có một số ví dụ cụ thể hơn?


Tôi thấy bạn đến từ đâu - Tôi đã tự hỏi liệu tôi có quá khoa trương về việc chia thành các tệp riêng biệt hay không, nhưng nó giúp ích rất nhiều cho khả năng đọc, bảo trì và git mergeing. Ví dụ, tôi có một mô-đun để vẽ UI với OpenGL và tôi có .ccác tệp riêng cho từng thành phần mà tôi cần ( slider.c, indicator.cv.v.). Các triển khai phần tử này có chức năng vẽ chính có thể dài vài trăm dòng và một số lượng staticngười trợ giúp hợp lý bên trong. Họ cũng gọi một vài hàm hình học thuần túy từ bên trong mô-đun UI. Nghe có vẻ khá điển hình?
Dan Halliday

Một ví dụ tốt hơn về các tên dài có thể là mô-đun âm thanh của tôi - Tôi có một hệ thống phân cấp giống như Audio Module > Engines > Channels > Filterscó nghĩa là một cái gì đó giống như MyLibAudioEngines<EngineName>Channel<ActionName>. Hoặc trong bộ lọc của tôi mô hình con: MyLibAudioFilters<FilterName><Type><Action>vd. MyLibAudioFiltersBigSoundingCompressorFloat32Process
Dan Halliday

Không có điều đó có vẻ không hợp lý. Vài trăm dòng cho một hàm có vẻ hơi dài nhưng nếu những gì bạn đang vẽ là phức tạp, điều đó có thể khó tránh. Là chi nhánh nặng hoặc chỉ là rất nhiều hướng dẫn?
dùng2313838

Re: tên mô-đun âm thanh, bạn có thể viết tắt AudioFilters / AudioEngines vì ​​tôi nghĩ sẽ dễ dàng biết được đó là bộ lọc hay mô-đun dựa trên tên. Các loại vòng loại dữ liệu như Float32 cũng có thể được viết tắt (ví dụ 'd', 'f') vì các chữ viết tắt như vậy là phổ biến trong lập trình C.
dùng2313838

Cảm ơn câu trả lời của bạn - đôi khi cảm thấy gần như không thể có được thông tin tốt về kiến ​​trúc chương trình C (đặc biệt là so với các ngôn ngữ cấp cao hơn). Nhiều sách C tôi đã đọc hầu như không xem xét ý tưởng có nhiều mô-đun hoặc thậm chí nhiều hơn một tệp! Nhìn chung, tôi không nghĩ mình sẽ thay đổi nhiều, ngoại trừ việc xem xét liệu có nên sống với chữ viết tắt cho một số tên dài hơn hay không.
Dan Halliday

5

Quy ước thông thường cho các thư viện C là sử dụng tên thư viện làm tiền tố cho các tên có thể sử dụng được bên ngoài, vd

struct MyLibFoo;
void MyLibAFooAction(...);

Đối với các tên nội bộ thư viện vẫn phải truy cập được trong nhiều đơn vị của thư viện, không có quy ước nghiêm ngặt nào, nhưng tôi sẽ sử dụng tiền tố của tên thư viện và một dấu hiệu cho thấy đó là một hàm nội bộ. Ví dụ:

struct MyLibInternalFooBaz;
void MyLibInternalFooBazAction();

Tôi đồng ý rằng điều này có thể dẫn đến những cái tên khá dài và khó gõ, nhưng thật không may, đó là cái giá chúng ta phải trả cho việc không có một cơ chế như không gian tên C ++. Để giảm độ dài của tên, với chi phí rõ ràng, bạn có thể chọn sử dụng chữ viết tắt trong tên của mình, nhưng bạn phải cân nhắc cẩn thận những lợi thế và bất lợi.


3

Nếu bạn muốn tránh các tiền tố dài, bạn có thể viết tắt tên thư viện giống như những gì Apple làm trong iOS và OS X:

  • NSString là một chuỗi từ gốc NextStep của HĐH
  • CALayer là một lớp Hoạt hình lõi

1

Điều gì về việc có một biến cấu trúc toàn cầu được điền sẵn với các con trỏ hàm?

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};

Khai thác:

#include "lib.h"

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

Từ khóa tĩnh giới hạn phạm vi cho đơn vị dịch thuật để nó không va chạm với người khác.

Sau đó, người dùng có thể rút ngắn nó bằng cách sử dụng một con trỏ như thế YourApi *ya = &yourApi, sau đó sử dụngya->doFoo(...) .

Nó cũng cung cấp một cách hay để giả lập thư viện của bạn để thử nghiệm.


Mô hình thú vị, nó đòi hỏi một chút nồi hơi, nhưng điều này sẽ làm cho tự động hoàn thành hữu ích hơn nhiều.
Rick Yêu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.