Emin değilim ama bence cevabın hayır, ince sebeplerden dolayı hayır. Ben birkaç yıl önce Teorik Bilgisayar Bilimi üzerine sorulan ve burada sunacağız ötesine geçer bir cevap alamadım.
Çoğu programlama dilinde, bir Turing makinesini aşağıdaki şekillerde simüle edebilirsiniz:
- sonlu otomatın sonlu miktarda bellek kullanan bir program ile simüle edilmesi;
- bandın, mevcut pozisyondan önce ve sonra bandın içeriğini temsil eden bir çift tamsayı listesi ile simüle edilmesi. İşaretçiyi hareket ettirmek, listelerden birinin kafasını diğer listeye aktarmak anlamına gelir.
Bilgisayarda çalışan somut bir uygulamada, kaset çok uzarsa bellek yetersiz kalır, ancak ideal bir uygulama Turing makine programını güvenilir bir şekilde uygulayabilir. Bu, kalem ve kağıtla veya daha fazla belleğe sahip bir bilgisayar ve her kelime için daha fazla bit içeren bir mimariyi hedefleyen bir derleyici veya programın belleği tükenirse yapılabilir.
Bu, C'de çalışmaz, çünkü sonsuza dek uzayabilecek bağlantılı bir listeye sahip olmak imkansızdır: Düğüm sayısında her zaman bir sınır vardır.
Nedenini açıklamak için önce bir C uygulamasının ne olduğunu açıklamaya ihtiyacım var. C aslında programlama dilleri ailesidir. ISO C standardı sözdizimi ve semantik programlama dilleri ailesi (İngilizce izin verdiğini formalite düzeyiyle) (bu standardın daha doğrusu, belirli bir versiyonu) tanımlar. C bir çok tanımsız davranışa ve uygulama tanımlı davranışa sahiptir.. C'nin bir “uygulaması”, uygulama tarafından tanımlanan tüm davranışı kodlar (kodlanacak şeylerin listesi C99 için Ek J'de bulunur). C'nin her uygulaması ayrı bir programlama dilidir. “Uygulama” kelimesinin anlamının biraz tuhaf olduğuna dikkat edin: gerçekte ne anlama geldiği bir dil çeşididir, aynı dil değişkenini uygulayan birden fazla farklı derleyici program olabilir.
2CHAR_BITt
2CHAR_BIT×sizeof(t)
2CHAR_BIT×sizeof(void*)
Değerleri CHAR_BIT
ve sizeof(void*)
gözlemlenebilir olması nedeniyle hafızanız tükenirse, bu parametreler için programınızı daha büyük değerlerle çalıştırmaya devam edemezsiniz. Programı farklı bir programlama dili altında çalıştırıyor olacaksınız - farklı bir C uygulaması.
n×2CHAR_BIT×sizeof(void*)n
C doğrudan maksimum özyineleme derinliği empoze etmez. Bir uygulamanın en fazlaya sahip olmasına izin verilir, ancak bir uygulamanın da olmamasına izin verilir. Fakat bir işlev çağrısı ile ebeveyni arasında nasıl iletişim kurarız? Argümanları adreslenebilirlerse iyi değildir, çünkü dolaylı olarak özyinelemenin derinliğini sınırlar: çünkü bir işleve sahipseniz , aktif karelerdeki int f(int x) { … f(…) …}
tüm oluşumların kendi adresleri vardır ve bu nedenle iç içe aramaların sayısı numaralarla sınırlandırılır. olası adreslerden .x
f
x
AC programı adreslenemeyen depolamayı register
değişkenler halinde kullanabilir. “Normal” uygulamalar, adresi olmayan az sayıda, sonlu sayıda değişkene sahip olabilir, ancak teoride bir uygulama sınırsız miktarda register
depolamaya izin verebilir . Böyle bir uygulamada, bir fonksiyona sınırsız sayıda özyinelemeli çağrı yapabilirsiniz, argümanı olduğu sürece register
. Ancak argümanlar olduğu için register
, onlara bir işaretçi yapamazsınız ve bu yüzden verilerini açıkça kopyalamanız gerekir: işaretçilerden oluşan rastgele boyutta bir veri yapısını değil, yalnızca sınırlı miktarda veriyi geçirebilirsiniz.
Sınırlandırılmamış özyineleme derinliği ve bir işlevin yalnızca doğrudan arayandan ( register
argümanlar) veri alabilmesi ve verileri doğrudan arayana (geri dönüş değeri) geri getirebilmesi kısıtlamasıyla , deterministik aşağı itme otomatlarının gücünü elde edersiniz .
Daha ileri gitmek için bir yol bulamıyorum.
(Elbette, programın kaset içeriğini, dosya giriş / çıkış işlevleriyle harici olarak depolamasını sağlayabilirsiniz. Fakat daha sonra C'nin Turing tamamlandı mı, C artı sonsuz bir depolama sisteminin Turing tamamlandı mı olduğunu sormazsınız. Bu sorunun cevabı sıkıcı bir “evet” dır. Depolamayı bir Turing kahramanı - çağrı fopen("oracle", "r+")
, fwrite
buna ilk bant içeriği olarak tanımlayabilir fread
ve son bant içeriğini geri alabilirsiniz.)