Argc neden sabit değil?


104
int main( const int argc , const char[] const argv)

As Etkili C ++ Ürün # 3 devletler "Kullanım const mümkün olduğunda" ben "bu 'sabit' parametreleri yapmaz neden düşünmeye başlar const"?.

argcBir programda değerinin değiştirildiği herhangi bir senaryo var mı ?


38
Sen beyan etmek serbesttir argcolarak const.
Oliver Charlesworth

14
Bunu yapan birçok üretim kalitesi kodu gördüm:--argc
Aniket Inge

2
Bunun C mirasıyla ilgisi olduğunu düşünüyorum, ancak nasıl olduğunu bilmiyorum.
Luis Machuca

13
"Mümkün olduğunda const kullan" ifadesinin referansla geçen şeylere atıfta bulunduğundan şüpheleniyorum, burada işlev içindeki herhangi bir değişiklik işlevden çıktıktan sonra devam eder. Bu, bir tamsayı gibi değerle geçen şeyler için doğru değildir, bu yüzden onu yaparak kazanılacak hiçbir şey yoktur const; aslında geçiş argc, const intdaha sonra argcişlevin içinde bir sayaç olarak kullanamayacağınız anlamına gelir .
Steve Melnikoff

4
@SteveMelnikoff: constBir geçiş değeri parametresi yaparak kazanılacak hiçbir şey olmadığını kabul etmiyorum . Bkz. Örn. Stackoverflow.com/a/8714278/277304 ve stackoverflow.com/a/117557/277304
leonbloy

Yanıtlar:


114

Bu durumda tarih bir faktördür. C bu girdileri "sabit değil" olarak tanımladı ve mevcut C koduyla (iyi bir kısmı) uyumluluk, C ++ 'nın ilk hedeflerinden biriydi.

Gibi bazı UNIX API'leri getoptaslında manipüle eder argv[], bu constnedenle bu nedenle de yapılamaz .

(Bir kenara: İlginç bir şekilde, getoptprototipi değiştirmeyeceğini argv[]ancak işaret edilen dizeleri değiştirebileceğini öne getoptsürse de , Linux kılavuz sayfası argümanlarına izin verdiğini gösteriyor ve yaramaz olduklarını bildikleri anlaşılıyor . Grup bu permütasyondan bahsetmiyor.)

Koyarak constüzerine argcve argvçok almazdım, ve onu bu şekilde uygulamalarını programlama bazı eski usulle geçersiz olacaktır:

// print out all the arguments:
while (--argc)
    std::cout << *++argv << std::endl;

C dilinde bu tür programlar yazdım ve yalnız olmadığımı biliyorum. Örneği bir yerden kopyaladım .


1
-1 Re "getopt gibi bazı UNIX API'leri aslında argv [] 'yi işliyor, bu nedenle bu nedenle de const yapılamaz.". Bir özgürce bir üst düzey ekleyebilir constiçin argvherhangi bir C işlevi yapabileceklerini etkilemeden. Ayrıca getoptolarak ilan edilir int getopt(int argc, char * const argv[], const char *optstring);. Ve burada constüst seviye değil, işaretçilerin constonları değiştirmeme sözü olduğunu ilan ediyor (işaret ettikleri dizeler makul bir şekilde değiştirilebilir olsa da).
Şerefe ve hth. - Alf

2
Üzgünüm, baktığım dokümanlar tutarsız: imza böyle bir permütasyona izin vermiyor. Bkz örnek . Ancak, aşağıdaki metin izin verdiğini söylüyor. Yani, olumsuz oyu kaldırıyorum.
Şerefe ve hth. - Alf

1
Yani, olumsuz oyu kaldırabilmem için "kilidi açmak" için bazı düzenlemeler yapmanız gerekecek. Ve hayır, prototipi yanlış anlıyorsunuz. Sağladığım örneğe ve derleme hatası olan "salt okunur konum ataması" na bakın.
Şerefe ve hth. - Alf

1
@ Cheersandhth.-Alf: İlginç ... Başlıkta prototipe baktım ve char* const* ___argvorada var, ancak arayüz aslında bağlı const char **. Böyle bir kafa karışıklığı. Ben önceliğini karıştırmıştım []ve *bakımından const. Özür dilerim.
Joe Z

1
Bilginize: GNU getopt()standardı takip etmediğini biliyor çünkü POSIXLY_CORRECTdoğru davranmasını sağlamak için ortam değişkenine dikkat ediyor . Özellikle, POSIX bağımsız değişkenlere izin vermez ve ilk seçenek olmayan bağımsız değişkenden sonraki seçenekleri aramaz.
Jonathan Leffler

36

C standardı (ISO / IEC 9899: 2011) şöyle diyor:

5.1.2.2.1 Program başlatma

¶1 Program başlangıcında çağrılan işlev adlandırılır main. Uygulama, bu işlev için hiçbir prototip bildirmez. Dönüş türü bir int ile ve parametresiz olarak tanımlanmalıdır:

int main(void) { /* ... */ }

veya iki parametreli (burada argcve olarak anılacaktır argv, ancak herhangi bir isim kullanılabilir, çünkü bildirildikleri işlev için yereldirler):

int main(int argc, char *argv[]) { /* ... */ }

veya eşdeğer; 10) veya başka bir uygulama tanımlı şekilde.

¶2 Bildirilirlerse, mainişlevin parametreleri aşağıdaki kısıtlamalara uyacaktır :

  • Değeri argcnegatif olmayacaktır.
  • argv[argc] boş gösterici olacaktır.
  • Değeri argcsıfırdan büyükse, kapsayıcı argv[0]aracılığıyla dizi üyeleri argv[argc-1], program başlangıcından önce ana bilgisayar ortamı tarafından uygulama tanımlı değerler verilen dizelere işaretçiler içermelidir. Amaç, programın başlatılmasından önce belirlenen program bilgilerini barındırılan ortamda başka bir yerden sağlamaktır. Ana bilgisayar ortamı hem büyük hem de küçük harflerle dizeler sağlayamıyorsa, uygulama dizelerin küçük harfle alınmasını sağlamalıdır.
  • Değeri argcsıfırdan büyükse, ile gösterilen dize argv[0] program adını temsil eder; argv[0][0]program adı ana bilgisayar ortamında mevcut değilse boş karakter olacaktır. Değeri ise argcbirden büyük olduğu, dizeleri tarafından işaret argv[1]yoluyla argv[argc-1] program parametrelerini temsil eder.
  • Dizi tarafından işaret edilen parametreler argcve argvdizeler argv, program tarafından değiştirilebilir ve programın başlatılması ile programın sonlandırılması arasında son saklanan değerleri korunacaktır.

10) Böylece, intolarak tanımlanan bir typedef adı ile değiştirilebilir intveya türü argvolarak yazılabilir char **argv, vb.

Son mermi noktasına dikkat edin. Hem söyler argcve argvdeğiştirilebilir olmalıdır. Değiştirilmeleri gerekmez, ancak değiştirilebilirler.


İlginç. Yarı ilişkili bir notta, Qt'nin QApplication(argc,argv)kurucusunun referans olarak tanımlanmasıargc nedeniyle ortaya çıkan çökmeye neden olan bir hatayla karşılaştım . Bu beni şaşırttı.
HostileFork

23

argcmain()ön tarihler için işlev imzası olduğundan normalde sabit değildir const.

Argc bir yığın değişkeni olduğundan, onu değiştirmek kendi komut satırı işlemeniz dışında hiçbir şeyi etkilemez.

Elbette, constisterseniz bunu beyan etmekte özgürsünüz .


8

constBiçimsel bir argümandaki üst düzey , işlev türünün bir parçası değildir. İstediğiniz gibi ekleyebilir veya kaldırabilirsiniz: yalnızca işlev uygulamasındaki argümanla neler yapabileceğinizi etkiler.

Böylece, argcözgürce bir const.

Ancak , işlev imzasını değiştirmeden argvkarakter verilerini yapamazsınız const. Bu, standart mainişlev imzalarından biri olmadığı ve bir mainişlev olarak tanınması gerekmeyeceği anlamına gelir . Yani, iyi bir fikir değil.


mainOyuncak olmayan programlarda standart bağımsız değişkenlerin kullanılmamasının iyi bir nedeni , Windows'ta uluslararası karakterli dosya adları gibi gerçek program bağımsız değişkenlerini temsil edememesidir. Bunun nedeni, Windows'ta Windows ANSI olarak kodlanmış çok güçlü bir kuraldır. Windows'ta GetCommandLineAPI işlevi açısından daha taşınabilir argüman erişim olanağı uygulayabilirsiniz .


Özetle, hiçbir şey eklemenizi constengellemez argc, ancak en kullanışlı constolanı argvsize standart olmayan bir mainişlev verir, büyük olasılıkla bu şekilde tanınmaz. Ne mutlu ki (ironik bir şekilde) taşınabilir ciddi kod için standart argümanları kullanmamak için iyi nedenler var main. Oldukça basit, pratikte sadece İngilizce alfabe harfleriyle yalnızca eski ASCII'yi destekliyorlar.


1
Windows için cygwin veya UTF-8'i uygun şekilde destekleyen başka bir libc ile geliştirme yapıyorsanız (bildiğim kadarıyla şu anda cygwin tek olanıdır, ancak başka bir seçenek üzerinde çalışan biri var), standart main imza iyi çalışıyor ve şunları yapabilirsiniz: rastgele Unicode bağımsız değişkenleri alır.
R .. GitHub ICE'E YARDIM ETMEYİ DUR

@R Ayrıca çoğu * nix platformunda iyi çalışırlar. Sorun, çalıştıkları platformların olup olmadığı değildir. ama çok güzel bir girişim ve olurken ben de aynısını yapıyorum, az çok ciddiyim
Şerefe ve hth. - Alf

4

İmzası mainbir bakıma tarihî bir eserdir C. Tarihsel olarak Cyoktu const.

Bununla birlikte, const'in constetkileri yalnızca derleme zamanı olduğu için parametrenizi bildirebilirsiniz .


"Tarihsel C" dediğinizde burada ne kadar tarihsel konuşuyoruz?
Joe Z

8
constC89 / C90'a eklendi; ondan önce C'nin bir parçası değildi
Jonathan Leffler

@JonathanLeffler: Biliyorsun, bunu unutmuştum. C'yi 1992'de öğrendim. Bundan önce bir Pascal, BASIC ve assembly hacker'ıydım.
Joe Z

2

Çünkü argcyerel bir değişkendir (ve C ++ 'da bir referans ya da başka bir şey değildir) ve maingeriye dönük uyumluluk saçmalıklarının özel yeri, uygulamaları onu sabit yapmaya zorlamak için zorlayıcı bir neden olmaksızın ona büyük miktarda alan sağlar .

main() {}

int main() {}

main() { return 0; }

main(int argc, char* argv[]) { return 0; }

int main(const int argc, const char** argv) { /* no return*/ }

bunlar ve diğer birçok varyasyon, çok çeşitli C ve C ++ derleyicilerinde derlenecektir.

Yani sonuçta mesele argc const değil, sadece olması gerekmiyor, ama eğer olmasını istiyorsanız olabilir.

http://ideone.com/FKldHF , C örneği:

main(const int argc, const char* argv[]) { return 0; }

http://ideone.com/m1qc9c , C ++ örneği

main(const int argc) {}

Açıkça dönüş türü olmayan varyantların, C11 bir yana, C99'da artık geçerli olmadığını unutmayın, ancak derleyiciler geriye dönük uyumluluk nedeniyle bunlara izin vermeye devam eder. C ++ derleyicileri, dönüş türü olmayan değişkenleri kabul etmemelidir.
Jonathan Leffler

@JonathanLeffler Evet, yine de oradaki son ideone örneği ( ideone.com/m1qc9c ) G ++ 4.8.2 ile -std=c++11. Clang da kabul ediyor ama veriyor warning: only one parameter on 'main' declaration [-Wmain]ve MSVC sadece eksik dönüş türü belirticisi ve argc'ye referans olmaması konusunda protesto ediyor. Yine, '
shenanigans

1

Tarihsel nedenlerin yanı sıra, argc ve argv'i non-const , derleyici uygulamasının main argümanlarıyla ne yapacağınızı bilmemesidir, sadece size bu argümanları vermesi gerektiğini bilir.

Kendi işlevlerinizi ve ilgili prototiplerinizi tanımlarken, hangi parametreleri yapabileceğinizi bilirsiniz. const ve işlevinizin hangilerini değiştireceğini .

Bir uç noktaya bakıldığında, tüm işlevlerin tüm parametrelerinin bildirilmesi gerektiğini beyan edebilir constve daha sonra bunları değiştirmek için bir nedeniniz varsa (örneğin, bir dizide arama yapmak için bir dizini azaltmanız), constdeğişken olmayan yerel yapmanız gerekir. ve constargümanların değerlerini bu değişkenlere kopyalayın . Bu, yoğun çalışma ve gerçek bir fayda olmaksızın ekstra LOC sağlar. İyi bir statik analizci, bir argümanın değerini değiştirmiyorsanız bu durumu algılayacak ve parametreyi oluşturmanızı tavsiye edecektir const.

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.