Yapı tanımları .h mi yoksa .c dosyası mı olmalı?


104

Hem structüstbilgilerde hem de yalnızca bildirimlerde s'nin tam tanımlarını gördüm - bir yöntemin diğerine göre avantajı var mı?

Eğer bir fark yaratırsa, genellikle böyle bir yapı yazdım .h

typedef struct s s_t;

Düzenle

Açık olmak gerekirse, seçenekler başlık dosyasında bildirim ve sınıftaki tanım veya başlık dosyasında hem bildirim hem de tanımlamadır. Her ikisi de aynı kullanılabilirlikle sonuçlanmalı, biri bağlantı yoluyla olsa bile, değil mi?


Neredeyse yinelenen birçok kopya görüyorum, örneğin burada ama tam eşleşme yok. Bu konuda yanılıyorsam lütfen düzeltin.


2
Opak mı yoksa opak olmayan bir yapı mı istiyorsunuz?

4
Yan not, ile tanımlayıcılar _tPOSIX tarafından ayrılmıştır, bu nedenle bu genellikle kötü bir fikirdir. Sadece yapabilirsin typedef struct toto toto.
Jens Gustedt

_tBaşka yerlerde (örneğin, lighttp, linux) çokça kullanım gördüm ... ve şeylerin önüne projident_ ekliyorum, bu bir sorun olmamalı mı?
Aaron Yodaiken

Ve @WTP, opak olmayanın genellikle daha iyi ve daha çok kabul edildiğini düşünüyorum C, hayır ( FILEörnekle ne varsa vb.) Yani opak değil.
Aaron Yodaiken

Opak olmayan bir yapı ise, bir başlık dosyasına girmesi gerekir veya kodunuz DRY değildir (kendinizi tekrar etmeyin).

Yanıtlar:


109

Bu dosya için özel yapılar, .h dosyasındaki herhangi bir işlev tarafından kullanılıyorsa, .h dosyasında bir bildirimle .c dosyasına gitmelidir.

Kamusal yapılar .h dosyasına girmelidir.


4
Sanırım bu yanıta daha çok katılıyorum. Bu yapıyı başka herhangi bir .c dosyası aracılığıyla kullanıp kullanmamakla ilgili değil, yapının herkese açık (ve dolayısıyla erişilebilir) olarak kabul edilip edilmeyeceği ile ilgili.
c00kiemon5ter

@ τεκ Görünürlük globalve demek istiyorsun local? publicbir yapı içinde mantıklı değil. Tüm yapılar varsayılan olarak geneldir.
BugShotGG

3
@Geo Papas Bu, C publicile ilgili bir soru , C'de bir anahtar kelime değildir. Matthew Slattery'nin aşağıdaki cevabına bakarsanız, başlıkta yalnızca ileriye dönük bir bildirimin kullanılmasının, kullanıcı bir kullanıcının üyelerini kullanmaya çalıştığında nasıl bir derleyici hatasına neden olduğunu görebilirsiniz. özel (opak) yapı.
τεκ

69

Her ikisi de aynı kullanılabilirlikle sonuçlanmalı, biri bağlantı yoluyla olsa bile, değil mi?

Hayır, aynı başlığı içeren diğer .c dosyalarını düşündüğünüzde değil. Yapının tanımı derleyiciye görünür değilse, bu tanımın ayrıntıları kullanılamaz. Tanımsız bir bildirim (örneğin sadece struct s;), derleyicinin içeri bakmaya çalışırsa başarısız olmasına neden struct solurken, örneğin derlemesine izin verir struct s *foo;( foodaha sonra başvurulmadığı sürece ).

Şu api.hve api.c:

Definition in header:                 Definition in implementation:
+---------------------------------+   +---------------------------------+
| struct s {                      |   | struct s;                       |
|     int internal;               |   |                                 |
|     int other_stuff;            |   | extern void                     |
| };                              |   | api_func(struct s *foo, int x); |
|                                 |   +---------------------------------+
| extern void                     |   +---------------------------------+
| api_func(struct s *foo, int x); |   | #include "api.h"                |
+---------------------------------+   |                                 |
+---------------------------------+   | struct s {                      |
| #include "api.h"                |   |     int internal;               |
|                                 |   |     int other_stuff;            |
| void                            |   | };                              |
| api_func(struct s *foo, int x)  |   |                                 |
| {                               |   | void                            |
|     foo->internal = x;          |   | api_func(struct s *foo, int x)  |
| }                               |   | {                               |
+---------------------------------+   |     foo->internal = x;          |
                                      | }                               |
                                      +---------------------------------+

Bu API istemcisi her iki sürümde de çalışır:

#include "api.h"

void good(struct s *foo)
{
    api_func(foo, 123);
}

Bu, uygulama ayrıntılarında dolaşıyor:

#include "api.h"

void bad(struct s *foo)
{
    foo->internal = 123;
}

Bu, "başlıktaki tanım" sürümüyle çalışacak, ancak "uygulamadaki tanım" sürümüyle çalışmayacaktır, çünkü ikinci durumda derleyici yapının düzenini görmez:

$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$

Bu nedenle, "uygulamadaki tanım" versiyonu, özel uygulama ayrıntılarının yanlışlıkla veya kasıtlı olarak kötüye kullanılmasına karşı koruma sağlar.


3
sadece bu kod pencerelerini nasıl oluşturduğunuzu ve hala kodun içlerinde vurgulanmış olduğunu bilmek ister misiniz? Görünüşe göre bu OP stackoverflow'u kullanarak ayrıldı: '(Başka biri bana söyleyebilir mi ....
Mahesha999

Güzel örnek! Teşekkürler!
Victor Haine

Böyle bir örnek için teşekkür ederim! dereferencing pointer to incomplete typebenim durumumdu!
Timur Fayzrakhmanov

Herkese açık yapıların hepsinin kötü olmadığını eklemek isterim: örneğin
API'nizin

@ Mahesha999, orada sihir yok. SO, içine çöp koysanız bile kodu vurgular. Gönderide daha sonra komut satırı çıktısını vurgulamaya çalıştığına dikkat edin.
Winger Sendon

8

Yapı diğer derleme birimleri (.c dosyaları) tarafından kullanılacaksa, bunu başlık dosyasına yerleştirin, böylece gerektiğinde bu başlık dosyasını dahil edebilirsiniz.

Yapı yalnızca bir derleme biriminde (.c dosyası) kullanılıyorsa, onu o .c dosyasına yerleştirirsiniz.


3

Mesele şu ki, onu bir başlık dosyasına yerleştirmek, sadece o başlık dosyasını dahil ederek birden çok kaynak dosyadaki yapıyı (veya başka bir tanımı) kullanmanıza izin verir.

Ancak, yalnızca bir kaynak dosyadan kullanılacağından eminseniz, o zaman gerçekten bir fark yaratmaz.



-4

Genel olarak, bunları başlığa veya kaynak dosyalarına koymanızın büyük bir fark yaratacağını düşünmüyorum. Ancak, bir yapının üyelerine birden çok kaynak dosyadan erişmeniz gerekiyorsa, yapıyı bir başlık dosyasına koymak ve yapının gerekli olduğu diğer dosyalardan eklemek daha kolaydır.


8
-1: Eğer iyi bir yazılım mühendisliği (soyutlama, modülerlik, vb.) Önemsiyorsanız, o zaman yapı tanımını nereye koyduğunuz önemli olur
Paul R
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.