Bir keresinde linux'taki ana süreç fonksiyonunun yığınının içeriğiyle ilgilenmeye başladım. Biraz araştırma yaptım ve şimdi size sonucu sunuyorum.

Ana işlevi tanımlama seçenekleri:
1. int ana()
2. int main(int argc, char **argv)
3. int main(int argc, char **argv, char **env)
4. int main(int argc, char **argv, char **env, ElfW(auxv_t) auxv)
5. int main(int argc, char **argv, char **env, char **elma)

Argc - parametre sayısı
argv - komut satırı seçeneklerinin dizelerine yönelik boş uçlu bir işaretçi dizisi
env, ortam değişkeni dizelerine yönelik boş uçlu bir işaretçi dizisidir. NAME=VALUE biçimindeki her satır
auxv - yardımcı değerler dizisi (yalnızca PowerPC için kullanılabilir)
elma - yürütülebilir dosyanın yolu (MacOS ve Darwin'de)
Yardımcı vektör - farklı bir dizi Ek Bilgiler etkin kullanıcı kimliği, setuid bit bayrağı, bellek sayfa boyutu ve benzerleri gibi.

Yığın segmentinin boyutu, haritalar dosyasında görüntülenebilir:
cat /proc/10918/haritalar

7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0

Yükleyici, kontrolü main'e aktarmadan önce, komut satırı parametreleri, ortam değişkenleri ve bir yardımcı vektör dizilerinin içeriğini başlatır.
Başlatma işleminden sonra, yığının üst kısmı 64bit sürümü için şöyle görünür.
Kıdemli adres üstte.

1. 0x7ffffffff000 Yığın segmentinin en üst noktası. Çağrı bir segfault'a neden oluyor
0x7ffffffff0f8 HÜKÜMSÜZ geçersiz* 8 0x00"
2. dosya adı karakter 1+ "/tmp/a.out"
karakter 1 0x00
...
ortam karakter 1 0x00
...
karakter 1 0x00
3. 0x7fffffffe5e0 ortam karakter 1 ..
karakter 1 0x00
...
bağımsız değişken karakter 1 0x00
...
karakter 1 0x00
4. 0x7fffffffe5be bağımsız değişken karakter 1+ "/tmp/a.out"
5. Rastgele uzunluk dizisi
6. auxv için veriler geçersiz* 48"
AT_NULL Elf64_auxv_t 16 {0,0}
...
yardımcı Elf64_auxv_t 16
7. yardımcı Elf64_auxv_t 16 Örn.: (0x0e,0x3e8)
HÜKÜMSÜZ geçersiz* 8 0x00
...
ortam karakter* 8
8. 0x7fffffffe308 ortam karakter* 8 0x7fffffffe5e0
HÜKÜMSÜZ geçersiz* 8 0x00
...
bağımsız değişken karakter* 8
9. 0x7fffffffe2f8 bağımsız değişken karakter* 8 0x7fffffffe5be
10. 0x7fffffffe2f0 argc uzun int 8" argüman sayısı + 1
11. Yerel değişkenler ve bağımsız değişkenler, ana işlevinden önce çağrılan işlevler
12. yerel değişkenler ana
13. 0x7fffffffe1fc argc int 4 argüman sayısı + 1
0x7fffffffe1f0 bağımsız değişken karakter** 8 0x7fffffffe2f8
0x7fffffffe1e8 ortam karakter** 8 0x7fffffffe308
14. Değişkenler yerel işlevler

"- Belgelerdeki alanların açıklamalarını bulamadım, ancak çöplükte açıkça görülüyorlar.

32 bit için kontrol etmedim, ancak büyük olasılıkla boyutları ikiye bölmek yeterlidir.

1. Üst noktanın üzerindeki adreslere erişim Segfault'a neden olur.
2. Yürütülebilir dosyanın yolunu içeren bir dize.
3. Ortam değişkenleri içeren diziler dizisi
4. Komut satırı seçenekleriyle dizi dizileri
5. Rastgele uzunlukta bir dizi. Seçimi komutlarla kapatılabilir
sysctl -w kernel.randomize_va_space=0
echo 0 > /proc/sys/kernel/randomize_va_space
6. Yardımcı vektör için veriler (örneğin, "x86_64" dizesi)
7. Yardımcı vektör. Daha fazla detay aşağıda.
8. Ortam değişkeni dizeleri için boş uçlu işaretçi dizisi
9. Satır parametre dizelerini komuta etmek için boş uçlu işaretçiler dizisi
10. Komut satırı parametrelerinin sayısını içeren bir makine kelimesi ("yüksek" fonksiyonların argümanlarından biri, bkz. madde 11)
11. main(_start,__libc_start_main..) öncesinde çağrılan fonksiyonların yerel değişkenleri ve argümanları
12. Main içinde bildirilen değişkenler
13. Ana fonksiyon argümanları
14. Yerel fonksiyonların değişkenleri ve argümanları.

yardımcı vektör
i386 ve x86_64 için yardımcı vektörün ilk elemanının adresini alamazsınız, ancak bu vektörün içeriği başka yollarla elde edilebilir. Bunlardan biri, ortam değişkeni dizelerine işaretçi dizisinden hemen sonra bellek alanına erişmektir.
Bunun gibi bir şeye benzemeli:
#Dahil etmek #Dahil etmek int main(int argc, char** argv, char** env)( Elf64_auxv_t *auxv; //x86_64 // Elf32_auxv_t *auxv; //i386 while(*env++ != NULL); // yardımcı elemanın başlangıcını bulun ( auxv = (Elf64_auxv_t *)env; auxv->a_type != AT_NULL; auxv++)( printf("addr: %p type: %lx is: 0x%lx\n", auxv, auxv->a_type, auxv için vektör ->a_un .a_val); ) printf("\n (void*)(*argv) - (void*)auxv= %p - %p = %ld\n (void*)(argv)-(void*) (&auxv) =%p-%p = %ld\n ", (void*)(*argv), (void*)auxv, (void*)(*argv) - (void*)auxv, (void*) (argv) , (void*)(&auxv), (void*)(argv) - (void*)(&auxv)); printf("\n argc kopyası: %d\n",*((int *)( argv - 1 )); 0 döndür; )
Elf(32,64)_auxv_t yapıları /usr/include/elf.h içinde açıklanmıştır. linux-kernel/fs/binfmt_elf.c içindeki yapıları doldurma işlevleri

Vektörün içeriğini almanın ikinci yolu:
hexdump /proc/self/auxv

En okunabilir gösterim ayarlanarak elde edilir. Çevre değişkeni LD_SHOW_AUXV.

LD_SHOW_AUXV=1ls
AT_HWCAP: bfebfbff // işlemci yetenekleri
AT_PAGESZ: 4096 //hafıza sayfası boyutu
AT_CLKTCK: 100 // sıklık zamanlarını güncelle()
AT_PHDR: 0x400040 //başlık bilgisi
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 // yorumlayıcının adresi, yani ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //program giriş noktası
AT_UID: 1000 //kullanıcı ve grup kimlikleri
AT_EUID: 1000 //nominal ve etkin
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 // setuid bayrak kümesidir
AT_RANDOM: 0x7fff30bdc809 //Adres 16 rastgele bayt,
başlangıçta oluşturulan
AT_SYSINFO_EHDR: 0x7fff30bff000 // için kullanılan sayfaya işaretçi
//sistem çağrıları
AT_EXECFN: /bin/ls
AT_PLATFORM: x86_64
Solda değişkenin adı, sağda değer bulunur. Tüm olası değişken adları ve açıklamaları elf.h dosyasında bulunabilir. (AT_ ön ekine sahip sabitler)

main()'den dön
İşlem bağlamı başlatıldıktan sonra, kontrol main()'e değil, _start() işlevine aktarılır.
main() zaten __libc_start_main'den çağrılar. Bu son işlev ilginç bir özelliği vardır - main()'den sonra yürütülecek bir işleve bir işaretçi iletilir. Ve bu işaretçi yığından doğal olarak geçirilir.
Genel olarak, __libc_start_main bağımsız değişkenleri, glibc-2.11/sysdeps/ia64/elf/start.S dosyasına göre forma sahiptir.
/*
* __libc_start_main için argümanlar:
*out0:ana
*out1: argc
*out2: argv
* çıkış3: başlangıç
* out4: fini // main'den sonra çağrılan işlev
* out5: rtld_fini
*out6: stack_end
*/
Şunlar. fini işaretçisinin adresini almak için, son yerel değişken main'den iki makine kelimesini taşımanız gerekir.
İşte olanlar (işlerlik derleyici sürümüne bağlıdır):
#Dahil etmek geçersiz **ret; geçersiz *bırak; void foo()( void (*boo)(void); //function pointer printf("Yığın yeniden yaz!\n"); boo = (void (*)(void))leave; boo(); // fini ( ) int main(int argc, char *argv, char *envp) ( unsigned long int mark = 0xbfbfbfbfbfbfbfbf; // ret'ten işe işaretle = (void**)(&mark+2); // adresi çıkar, bir fonksiyon tamamlandıktan sonra çağrılır (fini) izin = *ret; // mağaza *ret = (void*)foo; // dönüş 0'ın üzerine yaz; // foo() çağrısı)

Umarım ilginç olmuştur.
İyi şanlar.

Yararlı ipucu için Xeor kullanıcısına teşekkürler.

C++ programlama dilinde bir konsol uygulaması oluştururken, buna çok benzer bir satır otomatik olarak oluşturulur:

int main(int argc, char* argv) // main() fonksiyon parametreleri

Bu satır başlık ana işlev main() , argс ve argv parametreleri parantez içinde belirtilir. Yani, program çalıştırılırsa Komut satırı, o zaman bu programa bazı bilgiler iletmek mümkündür, bunun için argc ve argv parametreleri vardır. argc parametresi int veri türündedir ve iletilen parametre sayısını içerir. ana işlev. Ayrıca, fonksiyonun adı ilk parametre olarak kabul edildiğinden, herhangi bir bilgi iletmesek bile, argc her zaman en az 1'dir. argv parametresi, dizelere yönelik bir işaretçi dizisidir. Komut satırından yalnızca dize türü veriler geçirilebilir. İşaretçiler ve dizeler, ayrı bölümler oluşturulmuş iki büyük konudur. Bu nedenle, herhangi bir bilginin iletilmesi argv parametresi aracılığıyla olur. Komut satırı üzerinden çalıştıracağımız bir program geliştirelim. Windows hattı, ve ona bazı bilgiler iletin.

// argc_argv.cpp: Konsol uygulaması için giriş noktasını belirtir. #include "stdafx.h" #include ad alanı std kullanarak; int main(int argc, char* argv) ( if (argc ><< argv<

// kod Kod::Bloklar

// Dev-C++ kodu

// argc_argv.cpp: Konsol uygulaması için giriş noktasını belirtir. #Dahil etmek ad alanı std kullanarak; int main(int argc, char* argv) ( if (argc > 1)// argümanları iletirsek, argc 1'den büyük olacaktır (argüman sayısına bağlı olarak) ( cout<< argv<

Programın hatalarını ayıkladıktan sonra, Windows komut satırını açın ve programımızın yürütülebilir dosyasını komut satırı penceresine sürükleyin, programın tam yolu komut satırında görüntülenecektir (ancak programın yolunu manuel olarak yazabilirsiniz), sonra basabileceğiniz GİRMEK ve program başlayacaktır (bkz. Şekil 1).

Şekil 1 - Ana işlevin parametreleri

Programı yeni çalıştırdığımız ve ona herhangi bir argüman iletmediğimiz için Argüman değil mesajı belirdi. Şekil 2, aynı programın komut satırı üzerinden başlatıldığını, ancak kendisine Açık argümanın iletildiğini gösterir.

Şekil 2 - Ana işlevin parametreleri

Argüman Open kelimesidir, şekilden de görebileceğiniz gibi, bu kelime ekranda belirdi. Birden fazla parametreyi virgülle ayırarak aynı anda iletebilirsiniz. Birkaç kelimeden oluşan bir parametrenin iletilmesi gerekiyorsa, bunlar çift tırnak içine alınmalıdır ve bu kelimeler bir parametre olarak kabul edilecektir. Örneğin, şekil programın başlatılmasını gösterir ve ona iki kelimeden oluşan bir argümanı iletir - Çalışır .

Şekil 3 - Ana işlevin parametreleri

Ve eğer tırnakları kaldırırsanız. O zaman sadece O kelimesini göreceğiz. Programı başlatırken herhangi bir bilgi iletmeyi düşünmüyorsanız, o zaman main() fonksiyonundaki argümanları kaldırabilir, bu argümanların isimlerini de değiştirebilirsiniz. Bazen argc ve argv parametrelerinde değişiklikler olabilir, ancak bunların tümü oluşturulan uygulamanın türüne veya geliştirme ortamına bağlıdır.

İsteğe bağlı ve adlandırılmış bağımsız değişkenler

İsteğe Bağlı Bağımsız Değişkenler

C# 4.0, bir yöntemi çağırırken argümanları belirtmenin kolaylığını artıran yeni bir özellik sunar. Bu araç denir isteğe bağlı argümanlar ve bir yöntem parametresi için varsayılan bir değer tanımlamanıza olanak tanır. Yöntem çağrıldığında parametre için karşılık gelen bir bağımsız değişken belirtilmemişse bu değer varsayılan olarak kullanılacaktır. Bu nedenle, böyle bir parametre için bir argüman belirtmek gerekli değildir. İsteğe bağlı bağımsız değişkenler, bazı parametrelere varsayılan bağımsız değişkenlerin uygulandığı yöntemleri çağırmayı kolaylaştırır. Ayrıca "kısa" bir yöntem aşırı yükleme biçimi olarak da kullanılabilirler.

İsteğe bağlı argümanlar eklemenin ana itici gücü, COM nesneleri ile etkileşimi basitleştirme ihtiyacıydı. Birkaç Microsoft nesne modeli (örneğin, Microsoft Office), çoğu uzun zaman önce yazılmış ve isteğe bağlı parametreleri kullanmak üzere tasarlanmış COM nesneleri aracılığıyla işlevsellik sağlar.

İsteğe bağlı bağımsız değişkenleri kullanma örneği aşağıda gösterilmiştir:

Sistemi Kullanmak; System.Collections.Generic kullanarak; System.Linq kullanarak; System.Text'i kullanarak; namespace ConsoleApplication1 ( class Program ( // b ve c bağımsız değişkenleri static çağrılırken isteğe bağlıdır int mySum(int a, int b = 5, int c = 10) ( return a + b + c; ) static void Main() ( int sum1 = mySum(3); int sum2 = mySum(3,12); Console.WriteLine("Sum1 = "+sum1); Console.WriteLine("Sum2 = "+sum2); Console.ReadLine(); ) )

Tüm isteğe bağlı argümanların mutlaka gerekli olanların sağında belirtilmesi gerektiği unutulmamalıdır. Yöntemlere ek olarak, yapıcılarda, dizin oluşturucularda ve temsilcilerde isteğe bağlı bağımsız değişkenler kullanılabilir.

İsteğe bağlı argümanların bir avantajı, programcının karmaşık yöntem ve kurucu çağrılarını işlemesini kolaylaştırmasıdır. Sonuçta, genellikle bir yöntemde genellikle gerekenden daha fazla parametre ayarlamak gerekir. Ve bu gibi durumlarda, bu parametrelerden bazıları, isteğe bağlı argümanların dikkatli kullanımıyla isteğe bağlı hale getirilebilir. Bu, yalnızca bu özel durumda önemli olan argümanların iletilmesi gerektiği ve aksi takdirde gerekli olması gereken tüm argümanların değil anlamına gelir. Bu yaklaşım, yöntemi rasyonalize etmemize ve programcının bunu işlemesini basitleştirmemize olanak tanır.

Adlandırılmış Argümanlar

.NET 4.0'ın piyasaya sürülmesiyle birlikte C#'a eklenen bir diğer özellik, sözde adlandırılmış argümanlar. Bildiğiniz gibi, argümanları bir metoda aktarırken, bir kural olarak, onların göründükleri sıra, parametrelerin metodun kendisinde tanımlandığı sıra ile eşleşmelidir. Başka bir deyişle, argüman değeri parametreye argüman listesindeki konumuna göre atanır.

Adlandırılmış bağımsız değişkenler bu sınırlamanın üstesinden gelmek için tasarlanmıştır. Adlandırılmış bir bağımsız değişken, değerinin atandığı parametrenin adını belirtmenize olanak tanır. Ve bu durumda, argümanların sırası artık önemli değil. Bu nedenle, adlandırılmış bağımsız değişkenler, sözdizimlerinde onlardan farklı olmalarına rağmen, daha önce bahsedilen nesne başlatıcılara biraz benzer. Ada göre bir bağımsız değişken belirtmek için aşağıdaki sözdizimi biçimini kullanın:

parametre_adı: değer

Burada Parametre adı değerin iletildiği parametrenin adını belirtir. Elbette parametre_adı, çağrılan yöntem için geçerli bir parametrenin adı olmalıdır.

Belirli argümanları C programlarına iletebilirsiniz. Main() hesaplamanın başında çağrıldığında, ona üç parametre iletilir. Bunlardan ilki, programa erişirken komut argümanlarının sayısını belirler. İkincisi, bu argümanları içeren karakter dizilerine yönelik bir işaretçi dizisidir (dize başına bir argüman). Üçüncüsü ayrıca karakter dizilerine yönelik bir dizi işaretçidir, işletim sistemi parametrelerine (ortam değişkenleri) erişmek için kullanılır.

Bu tür herhangi bir satır şu şekilde temsil edilir:

değişken = değer\0

Son satır, sondaki iki sıfır ile bulunabilir.

Main() işlevinin bağımsız değişkenlerini sırasıyla adlandıralım: argc, argv ve env (başka adlar da mümkündür). Ardından aşağıdaki açıklamalara izin verilir:

main(int argc, char *argv)

main(int argc, char *argv, char *env)

A: sürücüsünde bir program prog.exe olduğunu varsayalım. Bunu şöyle ele alalım:

A:\>prog.exe dosya1 dosya2 dosya3

Ardından argv, A:\prog.exe dizesinin bir göstergesidir, argv, dosya1 dizesinin bir göstergesidir ve bu böyle devam eder. İlk gerçek argümana argv ve son argümana argv ile işaret edilir. argc=1 ise, komut satırında program adından sonra parametre yoktur. Örneğimizde, argc=4.

özyineleme

Özyineleme, bir işlevin kendisini çağırdığı bir arama yöntemidir.

Özyinelemeli bir programın derlenmesinde önemli bir nokta, çıkışın organizasyonudur. Burada fonksiyonun sürekli olarak kendisini süresiz olarak çağıracağı hatasını yapmak kolaydır. Bu nedenle, özyinelemeli süreç, adım adım sorunu basitleştirmelidir, böylece sonunda özyinelemeli olmayan bir çözüm ortaya çıkar. Yığın taşmasına yol açabileceğinden özyineleme kullanmak her zaman istenmez.

Kütüphane Fonksiyonları

Programlama sistemlerinde, ortak sorunları çözmek için alt programlar kitaplıklarda birleştirilir. Bu görevler şunları içerir: matematiksel fonksiyonların hesaplanması, veri girişi/çıkışı, dizi işleme, işletim sistemi araçlarıyla etkileşim, vb. Kütüphane rutinlerinin kullanımı, kullanıcıyı uygun araçlar geliştirme ihtiyacından kurtarır ve ona ek bir hizmet sağlar. Kütüphanelerde bulunan fonksiyonlar programlama sistemi ile birlikte sağlanır. Bildirimleri *.h dosyalarında verilmiştir (bunlar sözde içerme veya başlık dosyalarıdır). Bu nedenle yukarıda da bahsedildiği gibi kütüphane fonksiyonlarına sahip programın başında aşağıdaki gibi satırlar bulunmalıdır:

#Dahil etmek<включаемый_файл_типа_h>

Örneğin:

#Dahil etmek

Kullanıcı programları ile yeni kitaplıkları genişletmek ve oluşturmak için olanaklar da vardır.

Global değişkenler, program süresince bellekte sabit bir yere atanır. Yerel değişkenler yığında saklanır. Aralarında dinamik ayırma için bir bellek alanı bulunur.

malloc() ve free() işlevleri, boş belleği dinamik olarak ayırmak için kullanılır. malloc() işlevi belleği ayırır, free() işlevi onu serbest bırakır. Bu işlevlerin prototipleri stdlib.h başlık dosyasında saklanır ve şöyle görünür:

void *malloc(size_t boyut);

void *serbest(void *p);

malloc() işlevi, void türünde bir işaretçi döndürür; doğru kullanım için, işlev değeri uygun türe bir işaretçiye dönüştürülmelidir. Başarı durumunda, işlev, boyut boyutundaki boş belleğin ilk baytına bir işaretçi döndürür. Yeterli bellek yoksa 0 değeri döndürülür.sizeof() işlemi bir değişken için gereken bayt sayısını belirlemek için kullanılır.

Bu işlevlerin kullanımına bir örnek:

#Dahil etmek

#Dahil etmek

p = (int *) malloc(100 * sizeof(int)); /* 100 için bellek ayır

tam sayılar */

printf("Bellek yetersiz\n");

için (i = 0; ben< 100; ++i) *(p+i) = i; /* Использование памяти */

için (i = 0; ben< 100; ++i) printf("%d", *(p++));

ücretsiz(p); /* Boş hafıza */

malloc() tarafından döndürülen işaretçiyi kullanmadan önce, yeterli bellek olduğundan emin olmanız gerekir (işaretçi boş değil).

önişlemci

Bir C önişlemcisi, bir derleyiciye girdi işleyen bir programdır. Önişlemci kaynak programa bakar ve aşağıdaki eylemleri gerçekleştirir: verilen dosyaları ona bağlar, ikameleri gerçekleştirir ve ayrıca derleme koşullarını yönetir. Önişlemci, # sembolü ile başlayan program satırları için tasarlanmıştır. Satır başına yalnızca bir komuta (önişlemci yönergesi) izin verilir.

Direktif

#define tanımlayıcı değiştirme

aşağıdaki program metninin adlandırılmış tanımlayıcıyı ikame metniyle değiştirmesine neden olur (bu komutun sonunda noktalı virgül bulunmadığına dikkat edin). Esasen, bu yönerge bir makro tanımı (makro) sunar; burada "tanımlayıcı" makro tanımının adıdır ve "ikame" önişlemcinin belirtilen adı program metninde bulduğunda değiştirdiği karakter dizisidir. Bir makronun adı genellikle büyük harfle yazılır.

Örnekleri düşünün:

İlk satır, programın MAX tanımlayıcısını 25 sabitiyle değiştirmesine neden olur. İkinci satır, metinde açılış kaşlı ayracı (() BEGIN.

Önişlemci, makro tanımlarının sembolik adları ile bunların kullanıldığı bağlam arasındaki uyumluluğu kontrol etmediğinden, bu tür tanımlayıcıların #define yönergesi ile değil, açık bir türe sahip const anahtar sözcüğü ile tanımlanması önerilir. gösterge (bu, C + + için daha doğrudur):

const int MAX = 25;

(varsayılan olarak ayarlandığı için int türü atlanabilir).

#define yönergesi şuna benziyorsa:

#define tanımlayıcı(tanımlayıcı, ..., tanımlayıcı) ​​değiştirme

ve ilk tanımlayıcı ile açılış parantezi arasında boşluk yoksa, bu argümanlarla birlikte bir makro ikame tanımıdır. Örneğin, aşağıdaki gibi bir çizginin ortaya çıkmasından sonra:

#define READ(val) scanf("%d", &val)

ifade READ(y); scanf("%d",&y); ile aynı işlem yapılır. Burada val bir argümandır ve argümanla birlikte makro değiştirme gerçekleştirilir.

Bir sonraki satırda devam eden ikamede uzun tanımlar varsa, bir sonraki devam eden satırın sonuna bir \ karakteri yerleştirilir.

Bir makro tanımına ## karakterleriyle ayrılmış nesneleri yerleştirebilirsiniz, örneğin:

#define PR(x, y) x##y

Bundan sonra, PR(a, 3) ikameyi a3 olarak adlandıracaktır. Veya örneğin bir makro tanımı

#define z(a, b, c, d) a(b##c##d)

z(sin, x, +, y)'yi sin(x+y) olarak değiştirecektir.

Bir makro bağımsız değişkeninin önüne yerleştirilen # karakteri, bunun bir dizeye dönüştürüldüğünü gösterir. Örneğin, yönergeden sonra

#define PRIM(var) printf(#var"= %d", var)

program metninin aşağıdaki parçası

şu şekilde dönüştürülür:

printf("yıl""= %d", yıl);

Diğer önişlemci yönergelerini tanımlayalım. #include yönergesi daha önce görüldü. İki şekilde kullanılabilir:

#include "dosya adı"

#Dahil etmek<имя файла>

Her iki komutun da etkisi, programa belirtilen ada sahip dosyaları dahil etmektir. İlki, geçerli dizinden veya önek olarak belirtilen dizinden bir dosya yükler. İkinci komut, dosyayı programlama sisteminde tanımlanan standart konumlarda arar. Adı çift tırnak içinde yazılan dosya belirtilen dizinde bulunamazsa, arama #include komutu için belirtilen alt dizinlerde devam eder.<...>. #include yönergeleri iç içe yerleştirilebilir.

Bir sonraki yönerge grubu, programın bölümlerini seçici olarak derlemenize izin verir. Bu işleme koşullu derleme denir. Bu grup #if, #else, #elif, #endif, #ifdef, #ifndef yönergelerini içerir. #if yönergesinin temel biçimi şöyledir:

#if sabit_ifade ifadesi_dizisi

Burada sabit ifadenin değeri kontrol edilir. Doğruysa, verilen ifade dizisi yürütülür ve yanlışsa, bu ifade dizisi atlanır.

#else yönergesinin eylemi, C dilindeki else komutunun eylemine benzer, örneğin:

#if sabit_ifade

deyim_sekansı_2

Burada, sabit ifadesi true ise, o zaman sıra_işlemcileri_1 yürütülür ve yanlışsa,_işleçler_2_dizisi yürütülür.

#elif yönergesi "else if" türünde bir eylem anlamına gelir. Kullanımının ana şekli aşağıdaki gibidir:

#if sabit_ifade

deyim_dizisi

#elif sabit_ifade_1

deyim_sequence_1

#elif sabit_ifade_n

sıra_ifadeler_n

Bu form, formun C dili yapısına benzer: if...else if...else if...

Direktif

#ifdef tanımlayıcısı

belirtilen tanımlayıcının şu anda tanımlı olup olmadığını ayarlar, yani. #define formunun direktiflerine dahil edilip edilmediği. Çizgiyi görüntüle

#ifndef tanımlayıcısı

belirtilen tanımlayıcının şu anda tanımsız olup olmadığını kontrol eder. Bu yönergelerden herhangi birini, muhtemelen bir #else ifadesi (#elif kullanılamaz) içeren ve #endif satırıyla biten rastgele sayıda metin satırı izleyebilir. Kontrol edilen koşul doğruysa, #else ile #endif arasındaki tüm satırlar yok sayılır ve yanlışsa, check ile #else arasındaki satırlar (#else kelimesi yoksa, #endif) yok sayılır. #if ve #ifndef yönergeleri iç içe yerleştirilebilir.

Direktifi Görüntüle

#undef tanımlayıcı

belirtilen tanımlayıcının tanımsız olarak değerlendirilmesine neden olur, yani. değiştirilemez.

Örnekleri düşünün. Üç direktif şunlardır:

WRITE tanımlayıcısının tanımlı olup olmadığını kontrol edin (yani #define WRITE... biçiminde bir komuttu) ve eğer öyleyse, WRITE adı tanımsız olarak kabul edilir, yani. değiştirilemez.

direktifler

#define WRITE fprintf

WRITE tanımlayıcısının tanımsız olup olmadığını kontrol edin ve eğer öyleyse, fprintf adı yerine WRITE tanımlayıcısı belirlenir.

#error yönergesi aşağıdaki biçimde yazılmıştır:

#error error_message

Program metninde oluşursa, derleme durur ve ekranda bir hata mesajı görüntülenir. Bu komut çoğunlukla hata ayıklama aşamasında kullanılır. Hata mesajının çift tırnak içine alınması gerekmediğini unutmayın.

#line yönergesi, C programlama sisteminde tanımlanan _LINE_ ve _FILE_ değişkenlerinin değerlerini değiştirmeye yöneliktir. _LINE_ değişkeni, yürütülmekte olan programın satır numarasını içerir. _FILE_ tanımlayıcısı, derlenmekte olan programın adını içeren bir dizeye işaretçidir. #line yönergesi şu şekilde yazılır:

#satır numarası "dosya adı"

Burada sayı, _LINE_ değişkenine atanacak herhangi bir pozitif tamsayıdır, dosya adı, _FILE_ değerini geçersiz kılan isteğe bağlı bir parametredir.

#pragma yönergesi derleyiciye bazı yönergeleri iletmenizi sağlar. Örneğin, çizgi

bir C programında derleme dili dizeleri olduğunu gösterir. Örneğin:

Bazı genel tanımlayıcıları veya makro adlarını (makro tanımlarının adları) göz önünde bulundurun. Bu tür beş ad tanımlanmıştır: _LINE_, _FILE_, _DATE_, _TIME_, _STDC_. Bunlardan ikisi (_LINE_ ve _FILE_) yukarıda zaten açıklanmıştır. _DATE_ tanımlayıcısı, kaynak dosyanın nesne koduna çevrildiği tarihi saklayan bir dize belirtir. _TIME_ tanımlayıcısı, kaynak dosyanın nesne koduna çevrildiği zamanı depolayan bir dize belirtir. Standart tanımlı makro adları kullanılıyorsa, _STDC_ makrosu 1 değerine sahiptir. Aksi takdirde bu değişken tanımlanmayacaktır.


Bazen bir programı başlatırken ona bazı bilgileri iletmek yararlıdır. Tipik olarak, bu bilgi, komut satırı argümanları aracılığıyla main() işlevine iletilir. Komut satırı argümanı program adından sonra işletim sistemi komut satırına girilen bilgilerdir. Örneğin, bir programı derlemeye başlamak için, komut isteminden sonra komut satırına aşağıdakini yazmanız gerekir:

CC program adı

program adı derlemek üzere olduğunuz programın adını belirten bir komut satırı argümanıdır.

Komut satırı argümanlarını kabul etmek için iki özel yerleşik argüman kullanılır: argc ve argv . argc parametresi komut satırındaki argümanların sayısını içerir ve bir tamsayıdır ve ilk argüman programın adı olduğundan her zaman en az 1'dir. Ve argv parametresi, dizgelere yönelik bir dizi işaretçiye yönelik bir işaretçidir. Bu dizide, her öğe bir komut satırı argümanına işaret eder. Tüm komut satırı bağımsız değişkenleri dizelerdir, bu nedenle herhangi bir sayının istenen ikili biçime dönüştürülmesi, geliştirildiğinde programda sağlanmalıdır.

İşte komut satırı argümanını kullanmanın basit bir örneği. Ekran, komut satırı argümanı olarak belirtilmesi gereken Merhaba kelimesini ve adınızı görüntüler.

#Dahil etmek #Dahil etmek int main(int argc, char *argv) ( if(argc!=2) ( printf("Adınızı girmeyi unuttunuz.\n"); exit(1); ) printf("Merhaba %s", argv) ; 0 döndür; )

Bu program adını (ad) verdiyseniz ve adınız Tom ise, programı çalıştırmak için komut satırına Tom adını girin. Programı çalıştırmanın bir sonucu olarak ekranda Merhaba Tom mesajı görünecektir.

Birçok ortamda, tüm komut satırı bağımsız değişkenleri bir boşluk veya sekme ile birbirinden ayrılmalıdır. Virgül, noktalı virgül ve benzeri karakterler ayırıcı olarak kabul edilmez. Örneğin,

Spot'u çalıştırın, çalıştırın

üç karakter dizisinden oluşurken

Eric, Rick, Fred

tek karakterli bir dizedir - virgüller genellikle sınırlayıcı olarak kabul edilmez.

Dize boşluk içeriyorsa, bazı ortamlarda birden çok argümanın yapılmasını önlemek için dize çift tırnak içine alınabilir. Sonuç olarak, tüm dize tek bir argüman olarak kabul edilecektir. İşletim sisteminizde komut satırı seçeneklerinin nasıl ayarlandığı hakkında daha fazla bilgi edinmek için o sistemin belgelerine bakın.

argv'yi doğru bir şekilde bildirmek çok önemlidir. İşte bunu en sık nasıl yaptıkları:

Karakter *argv;

Boş köşeli parantezler, dizinin belirsiz bir uzunluğa sahip olduğunu gösterir. Artık argv dizisini indeksleyerek bağımsız argümanlara erişebilirsiniz. Örneğin, argv, her zaman program adı olan ilk karakter dizesini gösterir; argv ilk argümana işaret eder, vb.

Komut satırı argümanlarını kullanmanın başka bir küçük örneği aşağıdaki geri sayım programıdır. Bu program bir değerden (komut satırında belirtilen) geri sayım yapar ve 0'a ulaştığında bip sesi çıkarır. Başlangıç ​​değerini içeren ilk argümanın standart fonksiyon atoi () kullanılarak bir tamsayı değerine dönüştürüldüğünü unutmayın. Komut satırının ikinci argümanı (ve programın adını üçüncü argüman olarak alırsak) "display" (ekrana çıktı) dizesiyse, geri sayımın sonucu (ters sırada) görüntülenecektir. ekranda.

/* Geriye sayacak program. */ #Dahil etmek #Dahil etmek #Dahil etmek #Dahil etmek int main(int argc, char *argv) ( int disp, say; if(argc<2) { printf("В командной строке необходимо ввести число, с которого\n"); printf("начинается отсчет. Попробуйте снова.\n"); exit(1); } if(argc==3 && !strcmp(argv, "display")) disp = 1; else disp = 0; for(count=atoi(argv); count; --count) if(disp) printf("%d\n", count); putchar("\a"); /* здесь подается звуковой сигнал */ printf("Счет закончен"); return 0; }

Komut satırı bağımsız değişkenleri belirtilmezse bir hata mesajı görüntüleneceğini unutmayın. Komut satırı argümanlarına sahip programlar genellikle aşağıdakileri yapar: kullanıcı bu programları gerekli bilgileri girmeden çalıştırdığında, argümanların nasıl doğru bir şekilde belirleneceğine dair talimatlar görüntülenir.

Komut satırı argümanlarından birinde tek bir karaktere erişmek için ikinci dizini argv'ye girin. Örneğin, aşağıdaki program, çağrıldığı tüm argümanları karakter karakter yazdırır:

#Dahil etmek int main(int argc, char *argv) ( int t, i; for(t=0; t)

Unutmayın, argv öğesinin ilk dizini dizeye erişim sağlar ve ikinci dizin de kendi karakterlerine erişim sağlar.

Genellikle argc ve argv, başladığında ihtiyaç duyacağı programa ilk komutları iletmek için kullanılır. Örneğin, komut satırı bağımsız değişkenleri genellikle dosya adı, seçenek veya alternatif davranış gibi bilgileri belirtir. Komut satırı bağımsız değişkenlerini kullanmak, programınıza "profesyonel bir görünüm" verir ve toplu iş dosyalarında kullanımını kolaylaştırır.

argc ve argv adları gelenekseldir ancak zorunlu değildir. Bu iki parametreyi main() işlevinde istediğiniz gibi adlandırabilirsiniz. Ayrıca, bazı derleyiciler main() için ek argümanları destekleyebilir, bu nedenle derleyicinizin belgelerini kontrol ettiğinizden emin olun.

Bir program komut satırı parametreleri gerektirmediğinde, en yaygın olanı main() işlevinin hiçbir parametreye sahip olmadığını açıkça bildirmektir. Bu durumda, bu işlevin parametre listesinde void anahtar sözcüğü kullanılır.