Sadece kendi argümanlarına genişleyen bir PROTOTYPE makrosunun amacı nedir?


82

İçeren bir başlık dosyam var

#define PROTOTYPE(s) s

Bunun anlamı ne? Görünüşe göre girişi kendisiyle değiştirecek.

Orada çevresindeki diğer direktifler TON vardır, ama onu tanımlanan varsa rulman sadece kontrol ettirmek için görünen tek: #ifndef PROTOTYPE. Bunu HDF4 başlık dosyalarındaki bazı yerlerde bulundu: #define PROTOTYPE. Yani bunların hiçbiri sorumu gerçekten açıklığa kavuşturmadı. Yine de oldukça yararsız görünüyor.

İşte nasıl kullanıldığı:

CS_RETCODE clientmsg_callback PROTOTYPE((
CS_CONTEXT * context,
CS_CONNECTION *connection,
CS_CLIENTMSG *clientmsg));

Bu, Sybase Open Client kullanan bir projenin parçasıdır. clientmsg_callback daha sonra burada kullanılır:

ct_callback(context, NULL, CS_SET, CS_CLIENTMSG_CB,
                  (CS_VOID *)clientmsg_callback);

Buradan örnek bir programdan çıkıyorum:

http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc35570.1570/html/clcprgde/clcprgde10.htm

clientmsg_callback daha sonra uygulanır. Bence örnek orijinal olarak C ++ yerine C ile yazılmıştı. Belki bununla bir ilgisi vardır?


6
Bunun yerine farklı bir tanıma sahip olabilecek yakınlarda #if/ #ifdef/ #ifndef/ #elseyönergeler var mı? Özellikle yakın diğer makrolar kullanıldığında bir fark yaratabilir #ya ##. Sadece yorum yapma tarzı olabilir. Gerçekten cevaplamak için yeterli bağlam yok.
aschepler

Genel bir cevap olarak: çünkü birinin değişmek için bir sebebi olabilir PROTOTYPE. Eğer kodda işe yaramaz görünen tuhaf tanımlar görürseniz, birisi bir şeyi rahatça değiştirmek isterse olası esnekliği düşünün.
Apollys

Yanıtlar:


130

Gerçekten, gerçekten erken C'nin eski günlerinde, prototip diye bir şey yoktu. İşlev bağımsız değişken listeleri, aşağıdaki gibi işlevin parantezlerinden sonra gelir :

square(x)
int x;
{
int y = x * x;
return y;
}

Elbette bu günlerde argümanlar parantez içine giriyor:

square(int x)
{
int y = x * x;
return y;
}

"Eksik" dönüş türüne dikkat edin; C işlevleri örtük olarak geri dönmek için kullanılırdı intve yalnızca farklı bir dönüş türüne ihtiyaç duyduğunuzda ne olduğunu söylemeniz gerekirdi.

İşlev bildirimlerinin başka bir kuralı daha vardı. K&R C'deki (eski sürüm) bir işlev bildiriminin hiçbir argümanı yoktu:

int square();

Ve ANSI C'deki işlev prototiplerinin bir argüman listesi vardır:

int square(int x);

Geçiş sırasında, insanlar her iki yolu da derleyebilmek için tuhaf makrolar kullandılar:

int square(PROTOTYPE(int x));

İle

#define PROTOTYPE(s)

bu ilk sürüme genişler.

İle

#define PROTOTYPE(s) s

ikinciye genişlerdi.

Sorudaki koddaki "ekstra" parantezlerle ilgili olarak, bağımsız değişken listesinde birden fazla bağımsız değişken olduğunda bunlara ihtiyaç duyulur. Bunlar olmadan, makro çağrının birden fazla argümanı vardır, bu nedenle tek bir argümanla tanımlanan bir makroyla eşleşmez:

PROTOTYPE(int x, int y)   // error: too many arguments
PROTOTYPE((int x, int y)) // ok: only one argument (enclosed in parentheses)

10
Vay. Geçmişten patlama. Yazılımdaki ilk işlerimden biri, bu şeyleri mevcut bir kod tabanından çıkarmaktı. Unix'in tek satırlık metin değiştirme programları dizisine sağlıklı bir saygı uyandırdı.
user4581301

15
Bu tanımların nasıl çalıştığını anlamıyorum #define PROTOTYPE(s), girdi ile nasıl int x;dönüşüyor x? Bana boş bir dizgiye
sarılmış

3
@Ferrybig - üzgünüm, işleri karıştırdım. Bu var prototip bu şekilde tanımlanmış olur. K&R C'de, bir prototipin argümanı yoktu ve ANSI C'de, görmeye alıştığımız argüman listesi stiline sahip.
Pete Becker

1
Bu uygulama zlib.h, OF()makro ile zlib kitaplığındaki başlıkta da görülebilir : github.com/madler/zlib/blob/master/zlib.h
Paul Belanger

@PaulBelanger Asıl tanım içindedir zconf.h.
SS Anne

16

Bunun gibi makrolar, şuna benzer bir şeye izin vermek için başlık dosyasındaki prototiplerde kullanılır:

int foo PROTOTYPE((int bar));

ANSI C algılanırsa ( __STDC__1 olarak tanımlanır), bu şu şekilde genişler:

int foo(int bar);

ANSI C algılanmadıysa, bu şu şekilde genişler:

int foo();

C standardize edilmeden önce yaygındı.

Bazı kütüphaneler hala bunu yapıyor; Eğer bakarsanız tcpd.h(eğer varsa), göreceksiniz:

/* someone else may have defined this */
#undef  __P

/* use prototypes if we have an ANSI C compiler or are using C++ */
#if defined(__STDC__) || defined(__cplusplus)
#define __P(args)       args
#else
#define __P(args)       ()
#endif

Bu onu iyi açıklıyor.

Çift parantezlere gelince, __P(arg1, arg2)bir sözdizimi hatası verir (makroya çok fazla argüman iletmek), oysa __P((arg1, arg2))iyi olur (parantez içinde sadece bir tane).

Bu __extension__((...))GNU C'deki ile benzerdir . GNU olmayan derleyicilerde, #define __extension__(unused)parantez içine sarılmış tek bir "argüman" verildiği gibi , sadece yarı taşınabilir koda sahip olmak.

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.