İsim alanlarına sahip olmak çoğu dil için akıllıca görünmüyor. Ama anlayabildiğim kadarıyla ANSI C bunu desteklemiyor. Neden olmasın? Bunu gelecekteki bir standarda dahil etmeyi planlıyor musunuz?
İsim alanlarına sahip olmak çoğu dil için akıllıca görünmüyor. Ama anlayabildiğim kadarıyla ANSI C bunu desteklemiyor. Neden olmasın? Bunu gelecekteki bir standarda dahil etmeyi planlıyor musunuz?
Yanıtlar:
C ad alanlarına sahiptir. Yapı etiketleri için biri ve diğer türler için. Aşağıdaki tanımı düşünün:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
İlki foo etiketine sahiptir ve daha sonra typedef ile foo türüne dönüştürülür. Hala isim çatışması olmuyor. Bunun nedeni, yapı etiketlerinin ve türlerinin (yerleşik türler ve typedef'ed türler) ayrı ad alanlarında yaşamasıdır.
C'nin izin vermediği şey, irade ile yeni ad alanı yaratmaktır . Bu bir dilde önemli görülmeden önce C standardize edildi ve ad alanlarının eklenmesi de geriye dönük uyumluluğu tehdit ediyordu, çünkü doğru çalışması için adların karıştırılması gerekiyordu. Bence bu felsefeden değil, teknik konulardan kaynaklanabilir.
DÜZENLEME: JeremyP neyse ki beni düzeltti ve kaçırdığım ad alanlarından bahsetti. Etiketler ve yapı / birleşim üyeleri için ad alanları vardır.
struct
tanım, üyeleri için yeni bir ad alanı bildirir. Bu gerçeğin istismar edilmesini savunmuyorum struct
ve statik üyeleri olamayacağı için onu istismar etmenin herhangi bir yolunun farkında değilim .
Tamlık için, C'de ad alanlarından elde edebileceğiniz "faydaları" elde etmenin birkaç yolu vardır.
En sevdiğim yöntemlerden biri, kitaplığınıza / vb. Arayüz olan bir dizi yöntem işaretçisi barındıran bir yapı kullanmaktır.
Daha sonra bu yapının tüm işlevlerinize işaret eden kitaplığınızın içinde başlattığınız bir harici örneğini kullanırsınız. Bu, istemcilerin ad alanına adım atmadan kitaplığınızda adlarınızı basit tutmanıza olanak tanır (genel kapsamdaki extern değişkeni dışında, 1 değişken ve muhtemelen yüzlerce yöntem ..)
Bazı ek bakımlar var, ancak minimum düzeyde olduğunu hissediyorum.
İşte bir örnek:
/* 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 */
Kullanımı . sözdizimi, klasik Library_function () Library_some_value yöntemi üzerinde güçlü bir ilişki oluşturur. Ancak bazı sınırlamalar vardır, biri için makroları işlev olarak kullanamazsınız.
library.method1()
mı?
.c
dosyalarımdaki tüm işlevlerimi varsayılan olarak statik yapmaya çalışıyorum , bu nedenle açığa çıkan işlevler dosyadaki const struct
tanımda açıkça gösterilenlerdir .c
.
function1
/ method2
ikisi ile derlerken -O2
ve -flto
. Bu tür kitaplıkları kendi kaynağınızla birlikte derlemediğiniz sürece, bu yaklaşım işlev çağrılarına biraz ek yük getirecektir.
C ad alanlarına sahiptir. Sözdizimi namespace_name
. Hatta onları olduğu gibi iç içe bile geçirebilirsiniz general_specific_name
. Her seferinde ad alanı adını yazmadan adlara erişebilmek istiyorsanız, ilgili ön işlemci makrolarını bir başlık dosyasına ekleyin, örn.
#define myfunction mylib_myfunction
Bu, isim bozmaktan ve bazı dillerin ad alanları sağlamak için taahhüt ettiği diğer zulümlerden çok daha temizdir.
Tarihsel olarak, C derleyicileri isimleri karıştırmazlar (Windows'ta yaparlar, ancak cdecl
çağırma kuralının karıştırılması yalnızca bir alt çizgi öneki eklemekten ibarettir).
Bu, diğer dillerdeki (assembler dahil) C kitaplıklarını kullanmayı kolaylaştırır ve extern "C"
C ++ API'leri için sarmalayıcıları sıklıkla görmenizin nedenlerinden biridir .
sadece tarihsel nedenlerle. o zaman kimse isim alanı gibi bir şeye sahip olmayı düşünmedi. Ayrıca dili gerçekten basit tutmaya çalışıyorlardı. Gelecekte sahip olabilirler
Cevap değil, yorum değil. C namespace
açıkça tanımlamanın bir yolunu sağlamaz . Değişken kapsamı vardır. Örneğin:
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);
}
Değişkenler ve işlevler için nitelikli isimler kullanabilirsiniz:
mylib.h
void mylib_init();
void mylib_sayhello();
İsim alanlarından tek farkı, alamayacağınız using
ve içe aktaramayacağınızdır from mylib
.
namespace mylib { void init(); void say_hello(); }
Ayrıca önemli olan son iki satırı da değiştiremezsiniz (ish).
ANSI C, ad alanlarından önce icat edildi.
Çünkü bu yeteneği C'ye eklemek isteyen insanlar bir araya gelmemiş ve derleyici yazar ekipleri ve ISO organları üzerinde bir miktar baskı uygulamak için organize olmamıştır.
C, C ++ gibi ad alanlarını desteklemez. C ++ ad alanlarının uygulanması, adları karıştırır. Aşağıda özetlenen yaklaşım, karıştırılmamış adlara sahipken C ++ 'daki ad alanlarından yararlanmanıza olanak tanır. Sorunun doğasının neden C'nin ad alanlarını desteklemediğinin farkındayım (ve önemsiz bir yanıt, uygulanmadığı için desteklememesi olabilir :)). Sadece birinin şablonların ve ad alanlarının işlevselliğini nasıl uyguladığımı görmesine yardımcı olabileceğini düşündüm.
C kullanarak ad alanlarından ve / veya şablonlardan nasıl yararlanılacağına dair bir eğitim yazdım.
C'deki ad alanları ve şablonlar
C'deki ad alanları ve şablonlar (Bağlantılı Listeler kullanarak)
Temel ad alanı için, bir kural olarak ad alanı adının önüne basitçe eklenebilir.
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
olarak yazılabilir
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, ... );
Ad alanı kavramını ve şablonları kullanan ihtiyaç duyduğum ikinci bir yaklaşım, makro birleştirmeyi kullanmak ve dahil etmektir. Örneğin, bir
template<T> T multiply<T>( T x, T y ) { return x*y }
şablon dosyalarını aşağıdaki gibi kullanma
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;
}
Artık int_multiply'yi aşağıdaki gibi tanımlayabiliriz. Bu örnekte, bir int_multiply.h / .c dosyası oluşturacağım.
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"
Tüm bunların sonunda, için bir işlev ve başlık dosyanız olacak.
int int_multiply( int x, int y ) { return x * y }
Bağlantılı listelerle nasıl çalıştığını gösteren, sağlanan bağlantılarla ilgili çok daha ayrıntılı bir eğitim oluşturdum. Umarım bu birine yardımcı olur!