"Statik" ve "statik satır içi" işlevi arasındaki fark nedir?


123

IMO'nun her ikisi de işlevin yalnızca çeviri biriminin kapsamına sahip olmasını sağlar.

"Statik" ve "statik satır içi" işlevi arasındaki fark nedir?

Neden inlinedosyaya değil de başlık dosyasına .ckoyulmalı?

Yanıtlar:


108

inlinederleyiciye, gerçek bir çağrı yürütmek yerine işlev içeriğini çağıran koda yerleştirmeyi denemesini söyler.

Sıklıkla çağrılan küçük işlevler için büyük bir performans farkı yaratabilir.

Ancak, bu sadece bir "ipucu" ve derleyici bunu göz ardı edebilir ve çoğu derleyici, mümkün olduğu durumlarda, optimizasyonların bir parçası olarak anahtar kelime kullanılmadığında bile "satır içi" yapmaya çalışacaktır.

Örneğin:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Bu sıkı döngü, her yinelemede bir işlev çağrısı gerçekleştirir ve işlev içeriği aslında derleyicinin çağrıyı gerçekleştirmek için koyması gereken koddan önemli ölçüde daha azdır. inlinetemelde derleyiciye yukarıdaki kodu eşdeğerine dönüştürmesi talimatını verecektir:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Gerçek işlev çağrısını atlama ve geri dönme

Açıkçası bu, gerçek bir kod parçası değil, noktayı gösteren bir örnektir.

statickapsamı ifade eder. C'de bu, işlevin / değişkenin yalnızca aynı çeviri birimi içinde kullanılabileceği anlamına gelir.


4
Hayır, statickapsamı ifade eder. C'de bu, işlevin / değişkenin yalnızca aynı çeviri birimi içinde kullanılabileceği anlamına gelir.
littleadv

8
Satır içi olarak bildirilen kodun üstbilgiye ait olduğuna dikkat etmek de önemlidir, burada normal (şablon olmayan) kaynak kodu birden fazla yeniden tanımlama hatasına neden olmadan başlıklara giremez. Dolayısıyla, bir şeyi satır içi olarak bildirirken bile, derleyici onu satır içi yapmamayı seçse bile, yine de devreye giren standart bir çoklu yeniden tanımlamadan kaçınma davranışı vardır.
VoidStar

13
@VoidStar Aslında static(olsun veya olmasın inline) başlıkta gayet iyi olabilir, neden olmasın. Şablonlar C ++ içindir, bu soru C ile ilgilidir
littleadv

2
@littleadv: İşlev tanımlarını başlık dosyalarına koymanın ana nedeni, onları inlineable yapmaktır, bu yüzden onları açıkça işaretlemek inlineiyi bir stildir, imo
Christoph

10
Aslında derleyiciye satır içi olarak herhangi bir girişimde bulunma talimatıinline vermez . Yalnızca programcının işlev gövdesini ODR ihlali olmadan çoklu çeviri birimlerine dahil etmesine izin verir. Bunun bir yan etkisi 's markaları mümkün derleyicisi için, bu zaman olacağı ediyorum işlevi satır içi aslında bunu yapmak için.
Ruslan

96

Varsayılan olarak, bir satır içi tanım yalnızca mevcut çeviri biriminde geçerlidir.

Depolama sınıfı ise extern, tanımlayıcının harici bağlantısı vardır ve satır içi tanım da harici tanımı sağlar.

Depolama sınıfı ise static, tanımlayıcının dahili bağlantısı vardır ve satır içi tanım diğer çeviri birimlerinde görünmezdir.

Depolama sınıfı belirtilmemişse, satır içi tanım yalnızca geçerli çeviri biriminde görülebilir, ancak tanımlayıcının hala harici bir bağlantısı vardır ve farklı bir çeviri biriminde bir dış tanım sağlanmalıdır. İşlev mevcut çeviri birimi içinde çağrılırsa, derleyici satır içi veya harici tanımı kullanmakta serbesttir.

Derleyici, tanımı mevcut çeviri biriminde görülebilen (ve bağlantı zamanı optimizasyonları sayesinde, farklı çeviri birimlerinde bile olsa, satır içi (ve satır içi değil) herhangi bir işlevi satır içi (ve satır içi olmamak) konusunda özgür olduğundan, C standardı gerçekten hesaba katmaz. that), çoğu pratik amaç için, staticve static inlineişlev tanımları arasında hiçbir fark yoktur .

inline(Gibi belirteci registerdepolama sınıfına) sadece bir derleyici ipucu ve derleyici tümüyle görmezden serbesttir. Standartlara uyumlu, optimize etmeyen derleyiciler yalnızca yan etkilerini dikkate almalıdır ve derleyicilerin optimize edilmesi, bu optimizasyonları açık ipuçları olsun veya olmasın yapacaktır.

inlineve registerprogramcı optimizasyonları imkansız hale getirecek kod yazdığında derleyiciye hatalar atması talimatını verdikleri için faydasız değildir: Harici bir inlinetanım iç bağlantıya sahip tanımlayıcılara referans veremez (çünkü bunlar farklı bir çeviri biriminde mevcut olmayacaktır) veya statik depolama süresi olan değiştirilebilir yerel değişkenler tanımlayın (çünkü bunlar, çeviri birimleri arasında durumu paylaşmazlar) ve register-kalifiye değişkenlerin adreslerini alamazsınız.

Kişisel olarak, üstbilgi dosyalarına işlev tanımlarını koymanın ana nedeni onları satır içi yapmak olduğundan, staticişlev tanımlarını başlıklarda işaretlemek inlineiçin de kullanıyorum.

Genel olarak, başlıklardaki bildirimlere ek olarak yalnızca static inlineişlev ve static constnesne tanımlarını kullanıyorum extern.

Daha önce inlinedepolama sınıfından farklı bir işlev yazmadım static.


8
Bu doğru cevap. inlineGerçekte satır içi yapmaya uygulanmış gibi konuşan herhangi bir cevap yanıltıcıdır ve muhtemelen yanlıştır. Hiçbir modern derleyici bunu satır içi bir ipucu olarak kullanmaz veya bir işlevin satır içi olarak yazılmasını sağlamak için bunu gerektirmez.
Tyg13

1
"Statik işlev tanımlarını satır içi başlıklarda işaretlemek için kuralı kullanın" için oy verildi.
John Z. Li

Cevabınızın tamamını okudum ve hala staticve arasındaki anlamsal farkı anlamadım static inline. Her ikisi de tanımı diğer çeviri birimlerine görünmez kılar. Peki static inlinebunun yerine yazmak için mantıklı bir neden ne olabilir static?
user541686

21

GCC ile olan deneyimlerime dayanarak bunu biliyorum staticve static inlinederleyicinin kullanılmayan işlevler hakkında nasıl uyarılar verdiğini bir şekilde farklılaştırıyorum. Daha doğrusu, staticişlevi bildirdiğinizde ve mevcut çeviri biriminde kullanılmadığında, derleyici kullanılmayan işlev hakkında uyarı üretir, ancak bu uyarıyı olarak değiştirerek engelleyebilirsiniz static inline.

Bu nedenle, bunun staticçeviri birimlerinde kullanılması gerektiğini ve kullanılmayan işlevleri bulmak için derleyicinin fazladan kontrolünden faydalanması gerektiğini düşünüyorum . Ve static inlineuyarı veren olmadan kaplı (nedeniyle dış bağlantı bulunmadığı için) olabilir işlevleri sağlamak için başlık dosyalarında kullanılmalıdır.

Ne yazık ki bu mantık için herhangi bir kanıt bulamıyorum. GCC belgelerinden bile, inlinekullanılmayan işlev uyarılarını engellediğine karar veremedim . Birisi bunun açıklamasına bağlantılar paylaşırsa memnun olurum.


1
Mmm, başka bir çeviri biriminde kullanılan (v8.0.1) ile oluştururken hala warning: unused function 'function' [clang-diagnostic-unused-function]bir static inlineişlev var clang-tidy. Ama kesinlikle, bu en iyi açıklamalardan biri ve static& inline!
DrumM

6

C'de, statictanımladığınız işlev veya değişkenin yalnızca bu dosyada kullanılabileceği anlamına gelir (yani derleme birimi)

Yani, static inlineyalnızca bu dosyada kullanılabilen satır içi işlevi anlamına gelir.

DÜZENLE:

Derleme birimi Çeviri Birimi olmalıdır


2
Ya da süslü bir deyişle: iç bağlantıları vardır.
K-ballo

@AlokSave: Derleme birimi ile çeviri birimi arasında bir fark var mı ? Öyleyse, C ++ dili bağlamında hangisi daha uygundur?
efsaneler2k

the compile unittranslation unit
Yanlışlıkla

Cevabınız tam değil, çünkü çeviri birimlerinde çoğunlukla başlık dosyalarında kullanılıyor.
DrumM

5

Dil düzeyinde değil, popüler uygulama düzeyinde olan bir fark: gcc'nin belirli sürümleri, static inlinevarsayılan olarak referans alınmayan işlevleri çıktıdan kaldırır , ancak staticbaşvurulmasa bile düz işlevleri korur. Emin bu geçerli olduğu hangi versiyonları değilim, ama pratik bir bakış açısından o her zaman kullanmak iyi bir fikir olabilir demektir inlineiçin staticbaşlıklardaki fonksiyonlar.


inlineTanım olarak kullanmaya ne dersiniz ? Bunu externişlevler için kullanmamayı da ima ediyor musunuz ?
new_perl

Bu, GCC'nin son sürümü için hala geçerli mi? Bir örnek olursanız ve GCC'nin hangi sürümünün bunu yaptığını listelerseniz cevabınız çok daha ilginç olacaktır.
Z bozonu

@Zboson: Bu bilgiye hemen sahip değilim ve şu anda pek çok gcc sürümünü kurmak ve test etmek için zamanım yok, ancak sahip olmanın yararlı bir bilgi olacağını kabul ediyorum. Muhtemelen gcc'nin kullanılmayan statik işlevleri / nesneleri optimize etmeye ilk başladığında, attribute((used))asm'nin başka türlü başvurulmayan staticişlevlere ve verilere başvurmasına izin vermek için geçmişine ve kullanımına bakarak öğrenebilirsiniz .
R .. GitHub ICE YARDIMINI DURDUR
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.