ANSI C neden ad alanlarına sahip değil?


93

İ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?


13
C ++ 'ı C ad alanı ile kullanın!
AraK

3
Elbette yapabilirim, ama yine de bilmek istiyorum
Pulkit Sinha

5
2 şey. Gereksiz ayırt edici bir sözdizimi: İsim alanlı diğer tüm diller sadece '.' Kullanır. ayırıcı olarak diğer '.' kullanımları ile belirsiz değildir. Daha da önemlisi, c ++ hiçbir zaman yönergeyi kullanan kapsamlı bir yönergeyi tanıtmadı. Bu, programcıların ad alanlarını global kapsam içine almak için yönergeleri aşırı kullandığı anlamına geliyordu. Bu, c ++ standartları komitesinin artık std :: 'ye yeni özellikler ekleyemeyeceği anlamına geliyordu, çünkü sonuç olarak kırılacak kod miktarı bölümlemeyi gereksiz hale getirdi.
Chris Becke

2
@Chris Becke: Ayırt edici sözdizimini seviyorum. İsim alanındaki bir sınıfa mı yoksa sınıftaki bir üyeye mi baktığımı bilmek isterim.
JeremyP

6
@ChrisBecke, bu birkaç yıl gecikti, ancak C ++ ad alanlarının kötü bir şekilde uygulandığını iddia etmeniz ilginçtir, bu nedenle C'de uygulanmamaları gerekir. Diğer diller yapabiliyorsa, neden değil onları C'ye tanıtmak?
weberc2

Yanıtlar:


68

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.


8
Aslında ikiden fazla isim boşluğu var. Bahsettiğiniz ikisine ek olarak, her yapı ve birliğin üyeleri için etiketler ve ad boşlukları için bir ad alanı vardır.
JeremyP

@JeremyP: Düzeltme için çok teşekkürler. Bunu sadece hafızamdan yazdım, standardı kontrol etmedim :-)

2
işlevler için ad alanı ne durumda?
themihai

8
Buna ad alanları denilebilir, ancak bunların OP'nin sorduğu türden ad alanları olmadığına inanıyorum.
avl_sweden

1
@jterm Hayır. C özelliklerini hacklemeyi savunmuyorum, sadece gerçekleri belirtiyorum. Her structtanım, üyeleri için yeni bir ad alanı bildirir. Bu gerçeğin istismar edilmesini savunmuyorum structve statik üyeleri olamayacağı için onu istismar etmenin herhangi bir yolunun farkında değilim .
JeremyP

101

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.


12
... ve derleyiciler, siz yaptığınız zaman derleme zamanında işlev işaretçisini "kaldıracak" kadar akıllı library.method1()mı?
einpoklum

1
Bu harika. Ekleyebileceğim bir şey, .cdosyalarımdaki tüm işlevlerimi varsayılan olarak statik yapmaya çalışıyorum , bu nedenle açığa çıkan işlevler dosyadaki const structtanımda açıkça gösterilenlerdir .c.
lastmjs

3
Bu harika bir fikir, ancak sabitler ve numaralandırmalarla nasıl başa çıkarsınız?
nowox

1
@einpoklum - Özür necro için, ama en azından sürümü 6.3.0 itibariyle, gcc gerçek adresini hesaplamak olacak function1/ method2ikisi ile derlerken -O2ve -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.
Alex Reinking

3
@AlexReinking: Bu güzel, ama bu işlevleri asla satır içi yapamayız. Ve - necro'ing harika, özür dilemeye gerek yok.
einpoklum

25

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.


24
Ben farklı görüyorum. Önişlemci ile zaten yapmak için önemsiz olan bir şeyi başarmak için dilbilgisini karmaşıklaştırmak, sembollere isim karıştırmak vb.
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

41
Bu konumu gerçekten nasıl destekleyebileceğinizi anlamıyorum. Javascript topluluğuna, diğer her sistemde ad alanlarını uygulamak için farklı bir dahili hackleme olduğunda projeleri entegre etme hakkında bilgi alın. Hiç kimsenin 'ad alanı' veya 'paket' anahtar kelimelerinin dillerine çok fazla karmaşıklık kattığından şikayet ettiğini duymadım. Öte yandan, makrolarla dolu kodların hatalarını gidermeye çalışmak çok hızlı olabilir!
weberc2

5
Pek çok insanın C ++ adının karıştırılmasından (hata ayıklama, araç zinciri, ABI uyumluluğu, dinamik sembol arama, ... bakış açılarından) ve belirli bir adın gerçekte neye atıfta bulunduğunu bilmemenin karmaşıklığından şikayet ettiğini duydum.
R .. GitHub BUZ YARDIMINI DURDUR

6
@R .. C ++ 'da karıştırılan isim standartlaştırılsaydı bu olmazdı. Bu tek başına ABI uyumluluğuna yardımcı olmaz, ancak kesinlikle ad eşleme sorununu çözer.
Malcolm

20
C insanlarının bunu gerçekten düz bir suratla tartışmasını akıl almaz buluyorum. C ++ 'da insanları üzen keskin kenarlı birçok özellik vardır. Ad alanları bu özelliklerden biri değildir. Harikalar, çok iyi çalışıyorlar. Ve kayıt için önişlemci ile hiçbir şey önemsiz değildir. Son olarak, isimleri tasfiye etmek önemsizdir, bunu sizin için yapacak birçok komut satırı aracı vardır.
Nir Friedman

12

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 .


2
Ama bu neden böyle bir sorun? Demek istediğim, tüm ad alanlı adların _da13cd6447244ab9a30027d3d0a08903 ile başlayacağını ve ardından adın (Bu yeni oluşturduğum bir UUID v4) olduğunu varsayalım. Bunun, bu belirli UUID'yi kullanan isimleri bozma ihtimali vardır, ancak bu şans esasen sıfırdır. Bu yüzden pratikte sadece_isimalanı_adlarını karıştırmada sorun olmayacaktır .
einpoklum

7

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


2
Standart komitede gelecekte C'ye ad alanları eklemek için herhangi bir hareket var mı? C / C ++ modülüne geçiş ile bu gelecekte daha kolay hale getirebilir mi?
lanoxx

1
@lanoxx Geriye dönük uyumluluk nedeniyle C'ye ad alanları ekleme isteği yoktur.
themihai

6

Cevap değil, yorum değil. C namespaceaçı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 usingve 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).
einpoklum

3

ANSI C, ad alanlarından önce icat edildi.


10
Öyleydi? İlk ANSI C spesifikasyonu 1989'du. Ad alanlarının (bir şekilde veya başka bir şekilde) o zamandan önce programlama dillerinde olduğundan oldukça eminim. Örneğin Ada, 1983'te standartlaştırıldı ve ad alanları olarak paketlere sahipti. Bunlar da esasen Modula-2 modüllerine dayanıyordu.
SADECE DOĞRU GÖRÜŞÜM

4
ANSI C'nin icadını, spesifikasyonunun resmi olarak kabul edildiği tarihe tarihlendirmezdim; dil önceden vardı ve şartname zaten orada olanı belgeliyordu. Her ne kadar bu sitedeki bazı cevaplardan, spesifikasyonun önce geldiğini ve ilk derleyicinin sonradan geldiğini düşünebiliriz.
Crashworks

ANSI C, ANSI C öncesi bazı önemli farklılıklara sahipti, ancak ad alanları onlardan biri değildi.
dan04

Bu arada, ad alanlarının ortaya çıkmasından çok sonra 2020'de yazıyorum. En son C standartları hala bunlara sahip değil. C'nin mantıklı olduğu kadarıyla, bu kesinlikle eksik olan bir özellik.

3

Çü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.


1
Bence C'de ad alanını ancak bu insanlar kendilerini organize edip ad alanı desteği olan bir uzantı (lar) oluşturursa göreceğiz. O zaman ISO organlarının, bunları standart olarak yayınlamaktan başka seçeneği kalmayacak (az ya da çok değişiklikle). Javascript (bu bakımdan C ile bazı benzerlikleri vardır) böyle yaptı.
themihai

3
@themihai: "bir uzantı oluştur" = ad alanlarını derlemek için gcc ve clang insanları alın.
einpoklum

1

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!


3
Bağlantılarınız ad alanlarının nasıl ekleneceğini açıklar. Ancak soru, ad alanlarının neden desteklenmediğiydi. Yani bu cevap bir cevap değildir ve onun yerine bir yorum olmalıdır.
Thomas Weller
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.