Có không gian tên dường như không có trí tuệ đối với hầu hết các ngôn ngữ. Nhưng theo như tôi có thể nói, ANSI C không hỗ trợ nó. Tại sao không? Có kế hoạch đưa nó vào một tiêu chuẩn trong tương lai không?
Có không gian tên dường như không có trí tuệ đối với hầu hết các ngôn ngữ. Nhưng theo như tôi có thể nói, ANSI C không hỗ trợ nó. Tại sao không? Có kế hoạch đưa nó vào một tiêu chuẩn trong tương lai không?
Câu trả lời:
C có không gian tên. Một cho các thẻ cấu trúc và một cho các loại khác. Hãy xem xét định nghĩa sau:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
Cái đầu tiên có tag foo, và cái sau được tạo thành type foo với typedef. Vẫn không có đụng độ tên tuổi nào xảy ra. Điều này là do các thẻ và kiểu cấu trúc (kiểu cài sẵn và kiểu định sẵn) sống trong các vùng tên riêng biệt.
Điều mà C không cho phép là tạo không gian tên mới theo ý muốn. C đã được chuẩn hóa trước khi điều này được coi là quan trọng trong một ngôn ngữ và việc thêm không gian tên cũng sẽ đe dọa khả năng tương thích ngược, vì nó yêu cầu tính năng quản lý tên để hoạt động đúng. Tôi nghĩ rằng điều này có thể là do kỹ thuật, không phải triết học.
CHỈNH SỬA: May mắn thay, JeremyP đã sửa cho tôi và đề cập đến những không gian tên mà tôi đã bỏ qua. Có không gian tên cho nhãn và cho cấu trúc / đoàn viên.
struct
định nghĩa khai báo một không gian tên mới cho các thành viên của nó. Tôi không ủng hộ việc khai thác sự thật đó, cũng như không biết về bất kỳ phương tiện khai thác nào vì struct
không thể có các thành viên tĩnh.
Để hoàn thiện, có một số cách để đạt được "lợi ích" mà bạn có thể nhận được từ không gian tên, trong C.
Một trong những phương pháp yêu thích của tôi là sử dụng cấu trúc chứa một loạt các con trỏ phương thức là giao diện cho thư viện của bạn / v.v.
Sau đó, bạn sử dụng một phiên bản bên ngoài của cấu trúc này mà bạn khởi tạo bên trong thư viện của mình trỏ đến tất cả các hàm của bạn. Điều này cho phép bạn giữ cho tên của mình đơn giản trong thư viện của bạn mà không cần bước vào không gian tên máy khách (ngoại trừ biến extern ở phạm vi toàn cục, 1 biến so với hàng trăm phương thức ..)
Có một số bảo trì bổ sung liên quan nhưng tôi cảm thấy rằng nó là tối thiểu.
Đây là một ví dụ:
/* interface.h */
struct library {
const int some_value;
void (*method1)(void);
void (*method2)(int);
/* ... */
};
extern const struct library Library;
/* interface.h */
/* interface.c */
#include "interface.h"
void method1(void)
{
...
}
void method2(int arg)
{
...
}
const struct library Library = {
.method1 = method1,
.method2 = method2,
.some_value = 36
};
/* end interface.c */
/* client code */
#include "interface.h"
int main(void)
{
Library.method1();
Library.method2(5);
printf("%d\n", Library.some_value);
return 0;
}
/* end */
Việc sử dụng. cú pháp tạo ra một liên kết mạnh mẽ qua phương thức Library_ function () Library_some_value cổ điển. Tuy nhiên, có một số hạn chế, bạn không thể sử dụng macro làm hàm.
library.method1()
?
.c
tệp của mình ở trạng thái tĩnh theo mặc định, do đó, các hàm duy nhất được hiển thị là những hàm được hiển thị rõ ràng trong const struct
định nghĩa trong .c
tệp.
function1
/ method2
khi biên dịch với cả -O2
và -flto
. Trừ khi bạn biên dịch các thư viện như vậy cùng với nguồn của riêng bạn, cách tiếp cận này sẽ thêm một số chi phí vào các lệnh gọi hàm của nó.
C có không gian tên. Cú pháp là namespace_name
. Bạn thậm chí có thể lồng chúng vào general_specific_name
. Và nếu bạn muốn có thể truy cập vào tên mà không cần viết ra tên vùng tên mọi lúc, hãy bao gồm các macro tiền xử lý có liên quan trong tệp tiêu đề, ví dụ:
#define myfunction mylib_myfunction
Điều này rõ ràng hơn rất nhiều so với việc xáo trộn tên và các hành vi tàn bạo khác mà một số ngôn ngữ nhất định cam kết cung cấp không gian tên.
Về mặt lịch sử, các trình biên dịch C không trộn tên (chúng làm được trên Windows, nhưng việc trộn lẫn cho cdecl
quy ước gọi chỉ bao gồm thêm tiền tố gạch dưới).
Điều này giúp bạn dễ dàng sử dụng thư viện C từ các ngôn ngữ khác (bao gồm cả trình hợp dịch) và là một trong những lý do tại sao bạn thường thấy extern "C"
trình bao bọc cho các API C ++.
chỉ là lý do lịch sử. không ai nghĩ đến việc có một cái gì đó giống như một không gian tên vào thời điểm đó. Ngoài ra, họ đã thực sự cố gắng giữ cho ngôn ngữ đơn giản. Họ có thể có nó trong tương lai
Không phải là một câu trả lời, nhưng không phải là một bình luận. C không cung cấp cách xác định namespace
rõ ràng. Nó có phạm vi thay đổi. Ví dụ:
int i=10;
struct ex {
int i;
}
void foo() {
int i=0;
}
void bar() {
int i=5;
foo();
printf("my i=%d\n", i);
}
void foobar() {
foo();
bar();
printf("my i=%d\n", i);
}
Bạn có thể sử dụng tên đủ điều kiện cho các biến và hàm:
mylib.h
void mylib_init();
void mylib_sayhello();
Sự khác biệt duy nhất với không gian tên là bạn không thể có using
và không thể nhập from mylib
.
namespace mylib { void init(); void say_hello(); }
cũng quan trọng (ish).
ANSI C được phát minh trước khi có không gian tên.
Bởi vì những người muốn thêm khả năng này vào C đã không tập hợp và tổ chức để gây áp lực lên nhóm tác giả trình biên dịch và các cơ quan ISO.
C không hỗ trợ không gian tên như C ++. Việc triển khai các không gian tên trong C ++ mang tên. Cách tiếp cận được nêu dưới đây cho phép bạn có được lợi ích của không gian tên trong C ++ trong khi có tên không bị xáo trộn. Tôi nhận ra rằng bản chất của câu hỏi là tại sao C không hỗ trợ không gian tên (và một câu trả lời tầm thường sẽ là không vì nó không được triển khai :)). Tôi chỉ nghĩ rằng nó có thể giúp ai đó biết cách tôi đã triển khai chức năng của các mẫu và không gian tên.
Tôi đã viết một hướng dẫn về cách tận dụng lợi thế của không gian tên và / hoặc mẫu bằng cách sử dụng C.
Không gian tên và mẫu trong C (sử dụng Danh sách được Liên kết)
Đối với không gian tên cơ bản, người ta có thể chỉ cần đặt trước tên không gian tên như một quy ước.
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
có thể được viết như
struct MY_OBJECT_HANDLE;
struct MY_OBJECT_HANDLE *my_object_init();
void my_object_destroy( MY_OBJECT_HANDLE * & h );
void my_object_do_something(MY_OBJECT_HANDLE *h, ... );
Cách tiếp cận thứ hai mà tôi cần sử dụng khái niệm không gian tên và mẫu là sử dụng nối macro và bao gồm. Ví dụ: tôi có thể tạo
template<T> T multiply<T>( T x, T y ) { return x*y }
sử dụng các tệp mẫu như sau
Multi-template.h
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
Multi-template.c
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
Bây giờ chúng ta có thể định nghĩa int_multiply như sau. Trong ví dụ này, tôi sẽ tạo một tệp int_multiply.h / .c.
int_multiply.h
#ifndef _INT_MULTIPLY_H
#define _INT_MULTIPLY_H
#ifdef _multiply_
#undef _multiply_
#endif
#define _multiply_(NAME) int ## _ ## NAME
#ifdef _multiply_type_
#undef _multiply_type_
#endif
#define _multiply_type_ int
#include "multiply-template.h"
#endif
int_multiply.c
#include "int_multiply.h"
#include "multiply-template.c"
Khi kết thúc tất cả những điều này, bạn sẽ có một hàm và tệp tiêu đề cho.
int int_multiply( int x, int y ) { return x * y }
Tôi đã tạo một hướng dẫn chi tiết hơn về các liên kết được cung cấp cho thấy cách nó hoạt động với các danh sách được liên kết. Hy vọng rằng điều này sẽ giúp ai đó!