Memiliki ruang nama sepertinya tidak perlu dipikirkan untuk kebanyakan bahasa. Tapi sejauh yang saya tahu, ANSI C tidak mendukungnya. Kenapa tidak? Adakah rencana untuk memasukkannya ke dalam standar masa depan?
Memiliki ruang nama sepertinya tidak perlu dipikirkan untuk kebanyakan bahasa. Tapi sejauh yang saya tahu, ANSI C tidak mendukungnya. Kenapa tidak? Adakah rencana untuk memasukkannya ke dalam standar masa depan?
Jawaban:
C memang memiliki ruang nama. Satu untuk tag struktur, dan satu untuk jenis lainnya. Perhatikan definisi berikut:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
Yang pertama memiliki tag foo, dan yang selanjutnya dibuat menjadi tipe foo dengan typedef. Masih tidak ada bentrokan nama yang terjadi. Ini karena tag dan tipe struktur (tipe bawaan dan tipe yang diketik) tinggal di ruang nama yang terpisah.
Yang tidak diizinkan C adalah membuat namespace baru dengan keinginan. C distandarisasi sebelum ini dianggap penting dalam suatu bahasa, dan menambahkan namespace juga akan mengancam kompatibilitas ke belakang, karena memerlukan name mangling agar berfungsi dengan benar. Saya pikir ini dapat dikaitkan karena teknis, bukan filosofi.
EDIT: Untungnya JeremyP mengoreksi saya dan menyebutkan ruang nama yang saya lewatkan. Ada ruang nama untuk label dan untuk anggota struct / union juga.
struct
definisi mendeklarasikan namespace baru untuk anggotanya. Saya tidak menganjurkan untuk mengeksploitasi fakta itu, saya juga tidak mengetahui cara apa pun untuk mengeksploitasinya karena struct
tidak boleh memiliki anggota statis.
Untuk kelengkapan ada beberapa cara untuk mencapai "manfaat" yang mungkin Anda peroleh dari namespace, di C.
Salah satu metode favorit saya adalah menggunakan struktur untuk menampung banyak penunjuk metode yang merupakan antarmuka ke perpustakaan Anda / dll ..
Anda kemudian menggunakan contoh eksternal dari struktur ini yang Anda inisialisasi di dalam perpustakaan Anda yang menunjuk ke semua fungsi Anda. Ini memungkinkan Anda untuk membuat nama Anda tetap sederhana di perpustakaan tanpa menginjak ruang nama klien (selain variabel eksternal pada cakupan global, 1 variabel vs mungkin ratusan metode ..)
Ada beberapa perawatan tambahan yang terlibat tetapi saya merasa ini minimal.
Berikut ini contohnya:
/* 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 */
Penggunaan. sintaks membuat asosiasi yang kuat atas metode Library_function () Library_some_value klasik. Namun ada beberapa batasan, untuk satu Anda tidak dapat menggunakan makro sebagai fungsi.
library.method1()
?
.c
file saya statis secara default, jadi satu-satunya fungsi yang diekspos adalah yang secara eksplisit diekspos dalam const struct
definisi di .c
file.
function1
/ method2
saat mengkompilasi dengan -O2
dan -flto
. Kecuali jika Anda mengompilasi pustaka tersebut bersama dengan sumber Anda sendiri, pendekatan ini akan menambahkan beberapa overhead ke pemanggilan fungsinya.
C memiliki ruang nama. Sintaksnya adalah namespace_name
. Anda bahkan dapat menyarangkannya seperti di general_specific_name
. Dan jika Anda ingin dapat mengakses nama tanpa menulis nama namespace setiap saat, sertakan makro preprocessor yang relevan di file header, mis.
#define myfunction mylib_myfunction
Ini jauh lebih bersih daripada merusak nama dan kekejaman lain yang dilakukan bahasa tertentu untuk memberikan ruang nama.
Secara historis, kompiler C tidak mengotak-atik nama (mereka melakukannya di Windows, tetapi penguraian untuk cdecl
konvensi pemanggilan hanya terdiri dari penambahan awalan garis bawah).
Ini membuatnya mudah untuk menggunakan pustaka C dari bahasa lain (termasuk assembler) dan merupakan salah satu alasan mengapa Anda sering melihat extern "C"
pembungkus untuk C ++ API.
hanya alasan sejarah. tidak ada yang berpikir untuk memiliki sesuatu seperti namespace pada saat itu. Juga mereka benar-benar berusaha menjaga bahasanya tetap sederhana. Mereka mungkin memilikinya di masa depan
Bukan jawaban, tapi bukan komentar. C tidak menyediakan cara untuk mendefinisikan namespace
secara eksplisit. Ini memiliki ruang lingkup variabel. Sebagai contoh:
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);
}
Anda dapat menggunakan nama yang memenuhi syarat untuk variabel dan fungsi:
mylib.h
void mylib_init();
void mylib_sayhello();
Satu-satunya perbedaan dari namespace adalah bahwa Anda tidak dapat using
dan tidak dapat mengimpor from mylib
.
namespace mylib { void init(); void say_hello(); }
yang juga penting (ish).
ANSI C ditemukan sebelum namespace ada.
Karena orang yang ingin menambahkan kemampuan ini ke C belum berkumpul dan mengatur untuk memberikan tekanan pada tim pembuat kompiler dan badan ISO.
C tidak mendukung namespace seperti C ++. Implementasi namespaces C ++ merusak nama-nama. Pendekatan yang diuraikan di bawah ini memungkinkan Anda untuk mendapatkan manfaat dari namespace di C ++ sambil memiliki nama yang tidak rusak. Saya menyadari bahwa sifat dari pertanyaannya adalah mengapa C tidak mendukung namespace (dan jawaban sepele adalah bahwa itu tidak karena tidak diterapkan :)). Saya hanya berpikir bahwa ini dapat membantu seseorang untuk melihat bagaimana saya telah mengimplementasikan fungsionalitas template dan namespace.
Saya menulis tutorial tentang cara mendapatkan keuntungan dari namespace dan / atau template menggunakan C.
Ruang nama dan templat di C (menggunakan Daftar Tertaut)
Untuk namespace dasar, cukup awali nama namespace sebagai konvensi.
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
dapat ditulis sebagai
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, ... );
Pendekatan kedua yang saya perlukan yang menggunakan konsep namespacing dan template adalah menggunakan penggabungan makro dan menyertakannya. Misalnya, saya dapat membuat file
template<T> T multiply<T>( T x, T y ) { return x*y }
menggunakan file template sebagai berikut
multiply-template.h
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
multiply-template.c
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
Sekarang kita dapat mendefinisikan int_multiply sebagai berikut. Dalam contoh ini, saya akan membuat file 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"
Di akhir semua ini, Anda akan memiliki file fungsi dan header untuk.
int int_multiply( int x, int y ) { return x * y }
Saya membuat tutorial yang jauh lebih rinci tentang tautan yang disediakan yang menunjukkan cara kerjanya dengan daftar tertaut. Semoga ini membantu seseorang!