რამდენიმე დეტალი ძირითადი ფუნქციის შესახებ. MAIN() ფუნქციის არგუმენტები

ფუნქციის დაწერის ძირითადი ფორმა ასეთია

დაბრუნების_ტიპის ფუნქცია_სახელი(parameter_list) { სხეულის_ფუნქცია) ფუნქციის მიერ დაბრუნებული მონაცემების ტიპი მითითებულია ელემენტის გამოყენებით დაბრუნების_ტიპი . ელემენტის ქვემოთ parameter_list გულისხმობს მძიმით გამოყოფილი ცვლადების სიას, რომელსაც შეუძლია მიიღოს ნებისმიერი არგუმენტი ფუნქციით.

C89-ში, თუ ფუნქციით დაბრუნებული მონაცემთა ტიპი ცალსახად არ არის მითითებული, მაშინ გათვალისწინებულია ტიპი int. C++-სა და C99-ში ნაგულისხმევი int ტიპი არ არის მხარდაჭერილი, თუმცა C++ შემდგენელთა უმეტესობა მაინც აკეთებს ამ ვარაუდს.

ფუნქციონალური პროტოტიპები

C++ ენაში ყველა ფუნქციას უნდა ჰქონდეს პროტოტიპები, ხოლო C ენაში პროტოტიპები ფორმალურად არჩევითი, მაგრამ ძალიან სასურველია. პროტოტიპის განმარტების ზოგადი ფორმა ასეთია.

დაბრუნების_ტიპის ფუნქცია_სახელი(parameter_list); მაგალითად. float fn(float x); //ან float fn(float);

C-ში, void საკვანძო სიტყვა გამოიყენება პარამეტრების სიის ნაცვლად, რათა მიუთითოთ ფუნქციის პროტოტიპი, რომელსაც არ აქვს პარამეტრები. C++-ში, ცარიელი პარამეტრების სია ფუნქციის პროტოტიპში ნიშნავს, რომ ფუნქციას არ აქვს პარამეტრები. სიტყვა void ამ შემთხვევაში არჩევითია.

მნიშვნელობების დაბრუნება (დაბრუნების განცხადება)

ფუნქციებში მნიშვნელობების დაბრუნება ხდება დაბრუნების განცხადების გამოყენებით. მას აქვს ორი სანოტო ფორმა.

დაბრუნება; დაბრუნება მნიშვნელობა;

C99-ში და C++-ში, დაბრუნების განცხადების ფორმა, რომელიც არ განსაზღვრავს დაბრუნების მნიშვნელობას, უნდა იქნას გამოყენებული მხოლოდ void ფუნქციებში.

ფუნქციის გადატვირთვა

C++-ში ფუნქციებს შეუძლიათ გადატვირთვა. როდესაც ამბობენ, რომ ფუნქცია გადატვირთულია, ეს ნიშნავს, რომ ორ ან მეტ ფუნქციას აქვს ერთი და იგივე სახელი, მაგრამ გადატვირთული ფუნქციის თითოეულ ვერსიას აქვს სხვადასხვა რაოდენობის ან ტიპის პარამეტრები. განვიხილოთ შემდეგი სამი გადატვირთული ფუნქციის მაგალითი.

Void func (int a) (cout

თითოეულ შემთხვევაში, არგუმენტების ტიპი და რაოდენობა გაანალიზებულია, რათა დადგინდეს func()-ის რომელი ვერსია იქნება გამოძახებული.

ნაგულისხმევი ფუნქციის არგუმენტების გავლა

C++-ში ფუნქციის პარამეტრს შეიძლება მიენიჭოს ნაგულისხმევი მნიშვნელობა, რომელიც ავტომატურად იქნება გამოყენებული, თუ ფუნქციის გამოძახებისას შესაბამისი არგუმენტი არ არის მითითებული. მაგალითად.

Void ფუნქცია (int a = 0, int b = 10)() //call func(); func(-1); func(-1, 99);

ცვლადების ფარგლები და სიცოცხლის ხანგრძლივობა.

C და C++ ენები განსაზღვრავენ ხილვადობის წესებს, რომლებიც ადგენენ ცნებებს, როგორიცაა ობიექტების ფარგლები და სიცოცხლის ხანგრძლივობა. არსებობს გლობალური მასშტაბი და ლოკალური.

გლობალურიფარგლები არსებობს ყველა სხვა სფეროს მიღმა. გლობალურ ასპექტში გამოცხადებული სახელი ცნობილია მთელი პროგრამისთვის. მაგალითად, გლობალური ცვლადი ხელმისაწვდომია პროგრამის ყველა ფუნქციის გამოსაყენებლად. გლობალური ცვლადები არსებობს პროგრამის სასიცოცხლო ციკლის განმავლობაში.

ადგილობრივიფარგლები განისაზღვრება ბლოკის საზღვრებით. ლოკალური ფარგლების ფარგლებში გამოცხადებული სახელი ცნობილია მხოლოდ ამ ფარგლებში. ლოკალური ცვლადები იქმნება ბლოკში შესვლისას და განადგურებულია მისგან გასვლისას. ეს ნიშნავს, რომ ლოკალური ცვლადები არ ინახავს მათ მნიშვნელობებს ფუნქციის ზარებს შორის. ზარებს შორის ცვლადი მნიშვნელობების შესანარჩუნებლად, შეგიძლიათ გამოიყენოთ სტატიკური მოდიფიკატორი.

რეკურსია

C და C++-ში ფუნქციებს შეუძლიათ საკუთარი თავის გამოძახება. ამ პროცესს ე.წ რეკურსიასდა ფუნქცია, რომელიც თავის თავს იძახებს, არის რეკურსიული. მაგალითად, გამოვიყენოთ fact() ფუნქცია, რომელიც ითვლის მთელი რიცხვის ფაქტორიალს.

Int ფაქტი (int n) ( int ans; თუ (n == 1) დააბრუნებს 1; ans = ფაქტი (n-1) * n; დაბრუნება ans; )

main() ფუნქცია

C/C++ პროგრამის შესრულება იწყება main() ფუნქციის შესრულებით. (Windows-ის პროგრამები უწოდებს WinMain() ფუნქციას);

main() ფუნქციას არ აქვს პროტოტიპი. აქედან გამომდინარე, შესაძლებელია main() ფუნქციის სხვადასხვა ფორმების გამოყენება. main() ფუნქციის შემდეგი ვარიანტები მოქმედებს როგორც C, ასევე C++-ისთვის.

Int main(); int main (int argc, char *argv)

როგორც ჩაწერის მეორე ფორმადან ჩანს, ვ. main() იღებს მინიმუმ ორ პარამეტრს. მათ უწოდებენ argc და argv. ეს არგუმენტები შეინახავს ბრძანების ხაზის არგუმენტების რაოდენობას და მათზე მითითებას. argc არის მთელი რიცხვის ტიპი და მისი მნიშვნელობა ყოველთვის იქნება მინიმუმ 1, რადგან, როგორც C და C++-ში, პირველი არგუმენტი ყოველთვის არის პროგრამის სახელი. argv პარამეტრი უნდა გამოცხადდეს სიმბოლოების მაჩვენებლების მასივად, სადაც თითოეული ელემენტი მიუთითებს ბრძანების ხაზის არგუმენტზე. ქვემოთ მოცემულია პროგრამის მაგალითი, რომელიც აჩვენებს ამ არგუმენტების გამოყენებას.

#შეიცავს namespace std-ის გამოყენებით; int main (int argc, char *argv) (თუ (argc

მაჩვენებლების გავლა

მიუხედავად იმისა, რომ C და C++ ენები ნაგულისხმევად იყენებენ პარამეტრს მნიშვნელობის მიხედვით, შეგიძლიათ ხელით შექმნათ ზარი f-ზე. მითითებით გავლის პარამეტრებით. ამისათვის თქვენ უნდა გადასცეთ მაჩვენებელი არგუმენტს. ვინაიდან ამ შემთხვევაში ფუნქციას გადაეცემა არგუმენტის მისამართი, გამოდის, რომ შესაძლებელია არგუმენტის მნიშვნელობის შეცვლა ფუნქციის გარეთ. მაგალითად.

Void swap (int *x, int *y) ( int temp; temp = *x; ​​*x = *y; *y = temp; ) //ზარის გაცვლა (&a, &b);

C++-ში ცვლადის მისამართი ავტომატურად გადაეცემა ფუნქციას. ეს ხორციელდება გამოყენებით მითითება-პარამეტრი. მითითების პარამეტრის გამოყენებისას არგუმენტის მისამართი გადაეცემა ფუნქციას და ფუნქცია მუშაობს არგუმენტზე და არა ასლზე. ბმული პარამეტრის შესაქმნელად, მის სახელს წინ უნდა უსწროთ ამპერსანტი (&). შიგნით ვ. ამ პარამეტრის გამოყენება შეიძლება ჩვეულებრივ, მაგალითად, ვარსკვლავის (*) ოპერატორის გამოყენების გარეშე.

Void swap (int &x, int &y)( int temp; temp = x; x = y; y = temp; ) //call swap (a, b);

ფუნქციის სპეციფიკატორები

C++ განსაზღვრავს სამ ფუნქციას:

  • ჩასმული
  • ვირტუალური
  • გამოკვეთილი

inline specifier არის მოთხოვნა შემდგენლის მიმართ: ნაცვლად ფუნქციის გამოძახების შექმნისა, გააფართოვეთ მისი კოდი პირდაპირ ხაზზე. თუ შემდგენელს არ შეუძლია სტრიქონში ფუნქციის ჩასმა, მას უფლება აქვს უგულებელყოს ეს მოთხოვნა. inline specifier-ს შეუძლია განსაზღვროს როგორც წევრი ფუნქციები, ასევე არაწევრი ფუნქციები.

როგორც ვირტუალური ფუნქცია (ვირტუალური სპეციფიკატორის გამოყენებით) ვ. განისაზღვრება საბაზისო კლასში და გადაირიცხება წარმოებულ კლასში. ვირტუალური ფუნქციების მაგალითის გამოყენებით, შეგიძლიათ გაიგოთ, როგორ უჭერს მხარს C++ ენა პოლიმორფიზმს.

ექსპლიციტური სპეციფიკატორი გამოიყენება მხოლოდ კონსტრუქტორებზე. არანაირი კონვერტაცია არ განხორციელდება (ე.ი. გამოკვეთილი სპეციფიკატორი ქმნის "არაკონვერტირებად კონსტრუქტორს").

ფუნქციის შაბლონები

შაბლონის ფუნქციის განსაზღვრის ზოგადი ფორმა ასეთია.

შაბლონის ტიპი> დაბრუნების_ტიპის ფუნქცია_სახელი (parameter_list) ( //ფუნქციის სხეული ) აქ ტიპინიშნავს ჩანაცვლების ეტიკეტს იმ ტიპის მონაცემებისთვის, რომლებსაც ეს ფუნქცია რეალურად ეხება. შაბლონის განცხადებაში შეგიძლიათ განსაზღვროთ მრავალი მონაცემთა ტიპის პარამეტრი ელემენტების მძიმით გამოყოფილი სიის ფორმის გამოყენებით.

მოდით შევხედოთ მაგალითს.

შაბლონი void swap (X &a, X &b) ( X temp; temp = a; a = b; b = temp; ) //call int a, b; ათწილადი x, y; swap(a, b); swap (x, y);

ფუნქციის მაჩვენებლები

თქვენ შეგიძლიათ შექმნათ მაჩვენებელი ფუნქციაზე, ისევე როგორც ნებისმიერი სხვა C ენის ობიექტისთვის. სინტაქსი ასეთია.

დაბრუნების_ტიპი (*index_name)(ცვლადი_აღწერა); ეს დეკლარაცია ქმნის მაჩვენებელს მოწოდებულ ფუნქციაზე index_name , რომელიც შეიცავს ცვლადებს ცვლადი_აღწერა და რომელიც აბრუნებს ტიპის მნიშვნელობას დაბრუნების_ტიპი .

ფუნქციის გამოძახება შესაძლებელია მაჩვენებლის გამოყენებით შემდეგნაირად.

index_name = ფუნქცია_სახელი; ცვლადი = index_name (ცვლადები); აქ პირველი ხაზი ქმნის ფუნქციის მითითებას ფუნქცია_სახელი. მეორე ხაზი რეალურად იძახებს ფუნქციას მაჩვენებლის მეშვეობით index_name , რომელსაც გადაეცემა ცვლადები ცვლადები, მნიშვნელობა უბრუნდება ცვლადს ცვლადი .

შემდეგი მაგალითი გვიჩვენებს მაჩვენებლის შექმნას და ფუნქციის გამოძახების ორ გზას მაჩვენებლის საშუალებით, ასევე ფუნქციის პარამეტრად გადაცემას სხვა ფუნქციებზე.

ორმაგი y; ორმაგი (*p)(doublr x); p=ცოდვა; //ფუნქციის მაჩვენებელის შექმნა sin() y = (*p)(2.5); //გამოძახება y = p(2.5); //გამოძახება //ფუნქციის პარამეტრად გავლა double y; double f(double (*c)(double x), double y)( return c(y); //გადასული ფუნქციის გამოძახება მაჩვენებელ c და დააბრუნეთ მნიშვნელობა ) y = f(sin, 2.5); //სინ ფუნქციის გადაცემა f ფუნქციაზე, ასევე პარამეტრზე, რომელიც დამუშავდება

თქვენ ასევე შეგიძლიათ შექმნათ ფუნქციის მაჩვენებლების მასივები.

Int f1(void); int f2(void); int f3 (void); int (*p)(void) = (f1, f2, f3) y = (*p)(); //ფუნქციის გამოძახება f2 y = p(); //ფუნქციის გამოძახება f3

C ენების ოჯახის შესაძლებლობები მართლაც შეუზღუდავია, თუმცა, ამ თავისუფლებაში არის უარყოფითი მხარეებიც: პროგრამისტს ყოველთვის სჭირდება თვალი ადევნოს და გააკონტროლოს „ბუფერის გადინება“, რათა მოგვიანებით პროგრამა არ დაეჯახოს „ ლურჯი ეკრანი” Windows-ის უამრავ სხვადასხვა ვერსიაზე და ტექნიკის მომხმარებლებისთვის. იგივე კრეკერები და რევერსერები სპეციალურად ეძებენ დაუცველობას C პროგრამების კოდში, სადაც შესაძლებელია ნებისმიერი ვირუსის კოდის ჩადგმა, ამის შესახებ უფრო დეტალურად ავტორმა ისაუბრა თავის ვიდეოკურსში. იქ ბევრი რამ ვისწავლე და ახლა ჩემი კოდი გაცილებით უსაფრთხოა.

ფუნქცია მთავარი.

ყველა C და C++ პროგრამას უნდა ჰქონდეს მთავარი ფუნქცია;<значение>და თქვენზეა დამოკიდებული სად განათავსებთ მას. ზოგიერთი პროგრამისტი მას ათავსებს ფაილის დასაწყისში, ზოგი კი ბოლოს. თუმცა, მიუხედავად მისი პოზიციისა, თქვენ უნდა გახსოვდეთ შემდეგი: არგუმენტები "მთავარი" ფუნქციისთვის. Borland C++ დაწყების პროცედურა აგზავნის სამ პარამეტრს (არგუმენტს) მთავარ ფუნქციას: argc, argv და env. - argc, მთელი რიცხვი, არის მთავარ ფუნქციაზე გაგზავნილი ბრძანების ხაზის არგუმენტების რაოდენობა, - argv არის სტრიქონების მაჩვენებლების მასივი (char *).<=argc; i++) printf(" argv[%d]: %s\n",i,argv[i]); printf("Среда содержит следующие строки:\n"); for (i=0; env[i] != NULL; i++) printf(" env[%d]: %s\n",i,env[i]); return 0; } Предположим, что вы запускаете программу ARGS.EXE со следующей командной строкой: C:> args first_arg "არგი ბლანკებით" 3 4 "ბოლო ერთი" გაჩერება! კომენტარი. თუ გსურთ გაქცევის სიმბოლოების დამუშავება ყოველთვის მოხდეს, ე.ი. იმისათვის, რომ WILDARGS.OBJ ავტომატურად დაუკავშირდეს ბმულის რედაქტორს, თქვენ უნდა შეცვალოთ თქვენი სტანდარტული C?.LIB ბიბლიოთეკა, რომ შეიცავდეს ფაილს WILDARGS.OBJ. ამისათვის ამოიღეთ SETARGV ბიბლიოთეკიდან და დაამატეთ WILDARGS. ეს შეიძლება გაკეთდეს შემდეგი ბრძანებებით (ვვარაუდობთ, რომ სტანდარტული ბიბლიოთეკები და WILDARGS.OBJ შეიცავს მიმდინარე დირექტორიაში): TLIB აღწერილია მე-7 თავში, Utilities, მომხმარებლის სახელმძღვანელოს tlib cs -setargv +wildargs tlib cc -. setargv +wildargs tlib cm -setargv +wildargs tlib cl -setargv +wildargs tlib ch -setargv +wildargs კომპილაცია -p გადამრთველის გამოყენებით (პასკალის დარეკვის კონვენცია) თუ თქვენ შეადგენთ თქვენს პროგრამას პასკალის გამოძახების კონვენციის გამოყენებით (დაწვრილებით აღწერილია პასკალის გამოძახების კონვენციაში. თავი 9 "ინტერფეისი ასამბლეის ენასთან", "პროგრამის სახელმძღვანელო"), უნდა გახსოვდეთ, რომ მთავარი ფუნქცია აშკარად უნდა იყოს გამოცხადებული, როგორც C ფუნქცია , char *argv, char *env) ძირითადი ფუნქციის მიერ დაბრუნებული მნიშვნელობა.

DOS 3.x-ში და შემდეგში, argv განისაზღვრება, როგორც გასაშვები პროგრამის სრული გზა.

DOS-ის ადრინდელი ვერსიით გაშვებისას, argv მიუთითებს null სტრიქონზე ("").

argv მიუთითებს პირველ ბრძანების ხაზზე პროგრამის სახელის შემდეგ. argv მიუთითებს მეორე ბრძანების სტრიქონზე პროგრამის სახელის შემდეგ. argv მიუთითებს მთავარზე გაგზავნილ ბოლო არგუმენტზე. argv შეიცავს NULL-ს.ანუ, ძირითადი ფუნქციის დასაწყისი არის ღია ფრჩხილები, ხოლო მთავარი ფუნქციის დასასრული არის დახურვის ფრჩხილები. ორმაგი ხაზი მიუთითებს კომენტარის დასაწყისზე. კომენტარები იგნორირებულია შემდგენელის მიერ და ემსახურება კოდის ინფორმაციის გარკვევას.

C++-ში დაწერილ ყველა პროგრამას აქვს ფუნქცია მთავარი (), საიდანაც იწყება პროგრამა. ფუნქცია მთავარი (),როგორც წესი, აბრუნებს მისი შესრულების შედეგს, რომელსაც სიგნალი აქვს ინტ(მთლიანი - მთელი რიცხვი), რომელიც იწერება ფუნქციის წინ მთავარი (). სწორად, წარმატებით დასრულების შემდეგ, ფუნქცია მთავარი ()ბრუნდება შედეგად 0 . შედეგის მნიშვნელობა ნულის გარდა მიუთითებს პროგრამის არანორმალურ შეწყვეტაზე.

პროგრამის მიერ დაბრუნებული ღირებულება შეიძლება გამოყენებულ იქნას ოპერაციულ სისტემაში მომსახურების მიზნებისთვის.

პირველი პროგრამის ტიპიური მაგალითი ნებისმიერ პროგრამირების ენაზე არის ტექსტის გამომავალი "გამარჯობა, სამყარო!":

#შეიცავს int main() ( std::cout<< "Hello, World!\n"; }

მაგრამ ყველაფერი ასე მარტივია ამ პროგრამაში? ზოგადად, მხოლოდ ეს პატარა პროგრამა შეიცავს ინფორმაციის ძალიან დიდ ფენას, რომელიც გასაგები უნდა იყოს C++-ში განსავითარებლად.

  1. დირექტივა #შეიცავს
    Borland C++ დაწყების პროცედურა აგზავნის სამ პარამეტრს (არგუმენტს) მთავარ ფუნქციას: argc, argv და env.
    ეუბნება შემდგენელს, რომ აუცილებელია შეიტანოს გარკვეული სათაურის ფაილი, რომლის კომპონენტების გამოყენება იგეგმება ფაილში, სადაც ფუნქცია დეკლარირებულია. მთავარი () . iostreamარის სტანდარტული I/O ბიბლიოთეკა STL-დან. ანუ ბიბლიოთეკების ფუნქციონირება აქ უკვე გამოიყენება, თუმცა ისინი ენის სტანდარტია. და ბოლო წერტილი არის კუთხის ფრჩხილები, რომელშიც მდებარეობს ბიბლიოთეკის სახელი, რაც მიუთითებს იმაზე, რომ ეს არის გარე ფაილების ჩართვა პროექტში და არა ის, რაც პროექტის ნაწილია. იგივე ფაილები, რომლებიც პროექტის ნაწილია, შედის ჩვეულებრივი ციტატებით, მაგალითად #include "myclass.h".ბიბლიოთეკების ეს კავშირი სტანდარტულია. მაგალითად, in ვიზუალური სტუდიაამ სტანდარტის შეუსრულებლობა გამოიწვევს შეცდომებს.
  2. სტდარის სახელთა სივრცის გამოყენება, რომელშიც განთავსებულია გამომავალი განცხადება კოუტ.სახელთა სივრცეები დაინერგა C++-ში, რათა ამოეღოთ სახელების კონფლიქტი ბიბლიოთეკებსა და დეველოპერის პროექტს შორის, თუ სადმე არის დუბლიკატი ფუნქციების ან კლასის სახელები. ჯავა იყენებს პაკეტის სისტემას სახელების კონფლიქტების მოსაგვარებლად.

    კოუტარის გამომავალი ოპერატორი, რომელსაც აქვს გადატვირთული ოპერატორი << რათა თავიდან იქნას აცილებული ცალკეული ფუნქციის გამოყენება კონსოლში ტექსტის გამოსატანად.

ეს არის ფუნქციის ჩაწერის გარდა მთავარიშეიძლება ჰქონდეს განსხვავებული ფორმები, თუმცა ორი ჩანაწერი სტანდარტულია:

  1. int main()
  2. int main (int argc, char* argv)

თქვენ ასევე შეგიძლიათ იპოვოთ ჩანაწერები, როგორიცაა void main()და ა.შ. მაგრამ ეს არის მცდარი ჩანაწერები, თუმცა ზოგიერთ შემდგენელში ისინი შედგენილია, თუნდაც შეცდომებისა და გაფრთხილებების გარეშე.

ჩანაწერზე int main (int argc, char* argv)არგუმენტები მიიღება:

  1. argc- მიუთითებს მიღებული არგუმენტების რაოდენობაზე. ყოველთვის მინიმუმ 1, რადგან პროგრამის სახელი ყოველთვის გადაცემულია
  2. არგვ- არგუმენტების მაჩვენებლების მასივი, რომლებიც გადაეცემა სიმებიანი ცვლადების სახით.

თუ argc 1-ზე მეტი, ეს ნიშნავს, რომ დამატებითი არგუმენტები იქნა მიღებული პროგრამის გაშვებისას.

შემოწმება შეიძლება ასე გამოიყურებოდეს:

#შეიცავს int main(int argc, char* argv) ( // თუ დამატებითი არგუმენტი გავიდა, თუ (argc > 1) ( // მაშინ შევეცდებით დაბეჭდოთ მიღებული არგუმენტი std::cout<< argv<

ზოგადად, არის უამრავი პუნქტი, რომელიც უნდა გაიგოს C++-ში, თუნდაც მცირე პროგრამისთვის, მაგრამ ეს მხოლოდ მას უფრო საინტერესოს ხდის ;-)

ერთ დღეს დავინტერესდი ლინუქსის პროცესის ძირითადი ფუნქციის სტეკის შინაარსით. ჩავატარე კვლევა და ახლა წარმოგიდგენთ შედეგს.

ძირითადი ფუნქციის აღწერის ვარიანტები:
1. int main()
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 **apple)

Argc - პარამეტრების რაოდენობა
argv - მაჩვენებლების null-ტერმინალური მასივი ბრძანების ხაზის პარამეტრების სტრიქონებზე
env არის მაჩვენებლების ნულ-ტერმინალური მასივი გარემოს ცვლადების სტრიქონებზე. თითოეული ხაზი ფორმატში NAME=VALUE
auxv - დამხმარე მნიშვნელობების მასივი (ხელმისაწვდომია მხოლოდ PowerPC-სთვის)
Apple - გზა შესრულებადი ფაილისკენ (MacOS-ზე და Darwin-ზე)
დამხმარე ვექტორი არის მასივი სხვადასხვა დამატებითი ინფორმაციით, როგორიცაა ეფექტური მომხმარებლის იდენტიფიკატორი, setuid bit ატრიბუტი, მეხსიერების გვერდის ზომა და ა.შ.

სტეკის სეგმენტის ზომა შეგიძლიათ იხილოთ რუკების ფაილში:
კატა /proc/10918/რუკები

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

სანამ ჩამტვირთველი გადასცემს კონტროლს მთავარზე, იგი ახდენს ბრძანების ხაზის პარამეტრების, გარემოს ცვლადების და დამხმარე ვექტორის მასივების ინიციალიზაციას.
ინიციალიზაციის შემდეგ, სტეკის ზედა ნაწილი ასე გამოიყურება 64-ბიტიანი ვერსიისთვის.
უფროსი მისამართი ზევით.

1. 0x7ffffffff000 სტეკის სეგმენტის ზედა წერტილი. ზარი იწვევს სეგფულს
0x7ffffffff0f8 NULL ბათილად * 8 0x00"
2. ფაილის სახელი char 1+ "/tmp/a.out"
char 1 0x00
...
env char 1 0x00
...
char 1 0x00
3. 0x7fffffffe5e0 env char 1 ..
char 1 0x00
...
არგვ char 1 0x00
...
char 1 0x00
4. 0x7fffffffe5be არგვ char 1+ "/tmp/a.out"
5. შემთხვევითი სიგრძის მასივი
6. მონაცემები auxv ბათილად * 48"
AT_NULL Elf64_auxv_t 16 {0,0}
...
auxv Elf64_auxv_t 16
7. auxv Elf64_auxv_t 16 მაგ.: (0x0e,0x3e8)
NULL ბათილად * 8 0x00
...
env char* 8
8. 0x7fffffffe308 env char* 8 0x7fffffffe5e0
NULL ბათილად * 8 0x00
...
არგვ char* 8
9. 0x7fffffffe2f8 არგვ char* 8 0x7fffffffe5be
10. 0x7fffffffe2f0 argc ხანგრძლივი ინტ 8" არგუმენტების რაოდენობა + 1
11. ლოკალური ცვლადები და ფუნქციების არგუმენტები გამოძახებული main-მდე
12. ლოკალური ცვლადები მთავარი
13. 0x7fffffffe1fc argc ინტ 4 არგუმენტების რაოდენობა + 1
0x7fffffffe1f0 არგვ char ** 8 0x7fffffffe2f8
0x7fffffffe1e8 env char ** 8 0x7fffffffe308
14. ლოკალური ფუნქციის ცვლადები

" - მე ვერ ვიპოვე ველების აღწერილობები დოკუმენტებში, მაგრამ ისინი აშკარად ჩანს ნაგავსაყრელზე.

მე არ შემიმოწმებია 32 ბიტი, მაგრამ დიდი ალბათობით საკმარისია მხოლოდ ზომების ორზე გაყოფა.

1. ზედა წერტილის ზემოთ მისამართებზე წვდომა იწვევს Segfault-ს.
2. სტრიქონი, რომელიც შეიცავს შესრულებადი ფაილის გზას.
3. სტრიქონების მასივი გარემოს ცვლადებით
4. სტრიქონების მასივი ბრძანების ხაზის პარამეტრებით
5. შემთხვევითი სიგრძის მასივი. მისი შერჩევა შეიძლება გამორთოთ ბრძანებებით
sysctl -w kernel.randomize_va_space=0
echo 0 > /proc/sys/kernel/randomize_va_space
6. მონაცემები დამხმარე ვექტორისთვის (მაგალითად, სტრიქონი „x86_64“)
7. დამხმარე ვექტორი. დამატებითი დეტალები ქვემოთ.
8. გარემოს ცვლადების სტრიქონების მაჩვენებლების ნულ-ტერმინალური მასივი
9. მაჩვენებლების ნულ-ტერმინალური მასივი ბრძანების ხაზის პარამეტრების სტრიქონებზე
10. ავტომატური სიტყვა, რომელიც შეიცავს ბრძანების ხაზის პარამეტრების რაოდენობას („ძირითადი“ ფუნქციების ერთ-ერთი არგუმენტი, იხილეთ პუნქტი 11)
11. ლოკალური ცვლადები და ფუნქციების არგუმენტები გამოძახებული main(_start,__libc_start_main..)
12. ძირითადში დეკლარირებული ცვლადები
13.მთავარი ფუნქციის არგუმენტები
14. ლოკალური ფუნქციების ცვლადები და არგუმენტები.

დამხმარე ვექტორი
i386-ისთვის და x86_64-ისთვის შეუძლებელია დამხმარე ვექტორის პირველი ელემენტის მისამართის მიღება, მაგრამ ამ ვექტორის შიგთავსის მიღება შესაძლებელია სხვა გზით. ერთ-ერთი მათგანია მეხსიერების არეზე წვდომა გარემოს ცვლადების სტრიქონების მაჩვენებლების მასივის უკან.
ეს უნდა გამოიყურებოდეს დაახლოებით ასე:
#შეიცავს #შეიცავს int main (int argc, char** argv, char** env) (Elf64_auxv_t *auxv; //x86_64 // Elf32_auxv_t *auxv; //i386 while(*env++ != NULL); //ვეძებთ დასაწყისს დამხმარე ვექტორი (auxv = (Elf64_auxv_t *)env; auxv->a_type != AT_NULL; auxv++)(printf("addr: %p ტიპი: %lx არის: 0x%lx\n", auxv, auxv->a_type, auxv->a_un .a_val ) printf("\n (void*)(*argv) - (void*)auxv= %p - %p = %ld\n (void*)(argv)-(void*); )(&auxv) =%p-%p = %ld\n ", (ბათილი*)(*argv), (ბათილი*)auxv, (ბათილი*)(*argv) - (ბათილი*)auxv, (ბათილი*) )(argv) , (void*)(&auxv), (void*)(argv) - (void*)(&auxv) printf("\n argc ასლი: %d\n",*((int *)); (argv - 1 )));
Elf(32,64)_auxv_t სტრუქტურები აღწერილია /usr/include/elf.h. სტრუქტურების შევსების ფუნქციები linux-kernel/fs/binfmt_elf.c-ში

ვექტორის შინაარსის მისაღებად მეორე გზა:
hexdump /proc/self/auxv

ყველაზე წასაკითხი გამოსახულება მიიღება LD_SHOW_AUXV გარემოს ცვლადის დაყენებით.

LD_SHOW_AUXV=1 ლ
AT_HWCAP: bfebfbff //პროცესორის შესაძლებლობები
AT_PAGESZ: 4096 //მეხსიერების გვერდის ზომა
AT_CLKTCK: 100 //განახლების სიხშირე ჯერ()
AT_PHDR: 0x400040 //სათაურის ინფორმაცია
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 // თარჯიმნის მისამართი, ანუ ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //პროგრამის შესვლის წერტილი
AT_UID: 1000 //მომხმარებლის და ჯგუფის იდენტიფიკატორები
AT_EUID: 1000 //ნომინალური და ეფექტური
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 //აწეულია თუ არა სეტუიდური დროშა
AT_RANDOM: 0x7fff30bdc809 //მისამართი 16 შემთხვევითი ბაიტი,
გენერირდება გაშვებისას
AT_SYSINFO_EHDR: 0x7fff30bff000 //მაჩვენებელი გვერდისკენ, რომელიც გამოიყენება
//სისტემური ზარები
AT_EXECFN: /bin/ls
AT_PLATFORM: x86_64
მარცხნივ არის ცვლადის სახელი, მარჯვნივ არის მნიშვნელობა. ყველა შესაძლო ცვლადის სახელი და მათი აღწერილობა შეგიძლიათ იხილოთ elf.h ფაილში. (მუდმივია AT_ პრეფიქსით)

დაბრუნება main-დან ()
პროცესის კონტექსტის ინიციალიზაციის შემდეგ, კონტროლი გადადის არა main(), არამედ _start() ფუნქციაზე.
main() უკვე გამოძახებულია __libc_start_main-დან. ამ ბოლო ფუნქციას აქვს საინტერესო ფუნქცია - მას გადაეცემა მაჩვენებელი ფუნქციას, რომელიც უნდა შესრულდეს main()-ის შემდეგ. და ეს მაჩვენებელი ბუნებრივად გადაეცემა სტეკის მეშვეობით.
ზოგადად, __libc_start_main-ის არგუმენტები ასე გამოიყურება, ფაილის glibc-2.11/sysdeps/ia64/elf/start.S მიხედვით
/*
* არგუმენტები __libc_start_main-ისთვის:
* out0: მთავარი
* out1: argc
* out2: არგვ
* out3: საწყისი
* out4: fini //ფუნქციის გამოძახება main-ის შემდეგ
* out5: rtld_fini
* out6: stack_end
*/
იმათ. საბოლოო მაჩვენებლის მისამართის მისაღებად, თქვენ უნდა გადაიტანოთ ორი მანქანა სიტყვა ბოლო ლოკალური ცვლადის მთავარიდან.
აი, რა მოხდა (მუშაობა დამოკიდებულია შემდგენლის ვერსიაზე):
#შეიცავს void **ret; ბათილად *დატოვო; void foo())( void (*boo)(void); //ფუნქციის მაჩვენებელი printf("Stack rewrite!\n"); boo = (void (*)(void)) დატოვება; boo(); // fini () ) int main(int argc, char *argv, char *envp) ( ხელმოუწერელი გრძელი int ნიშანი = 0xbfbfbfbfbfbfbfbf; //ნიშანი, საიდანაც ვიმუშავებთ ret = (void**)(&mark+2); // ამოიღეთ მისამართი, გამოძახებული ფუნქცია (fini) leave = *ret = (void*)foo () ;

იმედია საინტერესო იყო.
წარმატებები.

მადლობა Xeor მომხმარებელს სასარგებლო რჩევისთვის.

შეგიძლიათ რამდენიმე არგუმენტი გადასცეთ C პროგრამებს. როდესაც main() გამოიძახება გაანგარიშების დასაწყისში, მას გადაეცემა სამი პარამეტრი. პირველი მათგანი განსაზღვრავს ბრძანების არგუმენტების რაოდენობას პროგრამაზე წვდომისას. მეორე არის მაჩვენებლების მასივი სიმბოლოების სტრიქონებზე, რომლებიც შეიცავს ამ არგუმენტებს (თითო არგუმენტი სტრიქონზე). მესამე არის ასევე სიმბოლოების სტრიქონების მაჩვენებლების მასივი, რომელიც გამოიყენება ოპერაციული სისტემის პარამეტრებზე წვდომისათვის (გარემოს ცვლადები).

ნებისმიერი ასეთი ხაზი წარმოდგენილია როგორც:

ცვლადი = მნიშვნელობა\0

ბოლო სტრიქონი შეიძლება მოიძებნოს ორი უკანა ნულით.

დავასახელოთ main() ფუნქციის არგუმენტები შესაბამისად: argc, argv და env (სხვა სახელები შესაძლებელია). შემდეგ მისაღებია შემდეგი აღწერილობები:

მთავარი (int argc, char *argv)

მთავარი (int argc, char *argv, char *env)

დავუშვათ, რომ დისკზე A: არის პროგრამა prog.exe. მოდით მივმართოთ მას შემდეგნაირად:

A:\>prog.exe ფაილი1 ფაილი2 ფაილი3

შემდეგ argv არის მაჩვენებელი A:\prog.exe სტრიქონზე, argv არის მაჩვენებელი ხაზის file1 და ა.შ. პირველ ფაქტობრივ არგუმენტზე მიუთითებს argv, ხოლო ბოლო - argv. თუ argc=1, მაშინ პროგრამის სახელის შემდეგ ბრძანების სტრიქონზე არ არის პარამეტრები. ჩვენს მაგალითში, argc=4.

რეკურსია

რეკურსია არის გამოძახების მეთოდი, რომელშიც ფუნქცია თავის თავს ეხება.

რეკურსიული პროგრამის შედგენისას მნიშვნელოვანი პუნქტია გამოსავლის ორგანიზება. მარტივი შეცდომა აქ არის ის, რომ ფუნქცია თანმიმდევრულად დაურეკავს თავის თავს განუსაზღვრელი ვადით. ამიტომ, რეკურსიულმა პროცესმა ეტაპობრივად უნდა გაამარტივოს პრობლემა ისე, რომ საბოლოოდ გამოჩნდეს მისთვის არარეკურსიული გადაწყვეტა. რეკურსიის გამოყენება ყოველთვის არ არის სასურველი, რადგან ამან შეიძლება გამოიწვიოს სტეკის გადინება.

ბიბლიოთეკის ფუნქციები

პროგრამირების სისტემებში, ხშირად წარმოქმნილი პრობლემების გადაჭრის რუტინები გაერთიანებულია ბიბლიოთეკებში. ასეთი ამოცანებია: მათემატიკური ფუნქციების გამოთვლა, მონაცემთა შეყვანა/გამოტანა, სტრიქონების დამუშავება, ოპერაციული სისტემის ინსტრუმენტებთან ურთიერთქმედება და ა.შ. ბიბლიოთეკის რუტინების გამოყენება მომხმარებელს ათავისუფლებს შესაბამისი ხელსაწყოების შემუშავების აუცილებლობისგან და უზრუნველყოფს მას დამატებითი სერვისებით. ბიბლიოთეკებში შემავალი ფუნქციები უზრუნველყოფილია პროგრამირების სისტემით. მათი დეკლარაციები მოცემულია *.h ფაილებში (ეს არის ე.წ. მოიცავს ან სათაურის ფაილები). ამიტომ, როგორც ზემოთ აღინიშნა, ბიბლიოთეკის ფუნქციების მქონე პროგრამის დასაწყისში უნდა იყოს ხაზები, როგორიცაა:

#შეიცავს<включаемый_файл_типа_h>

მაგალითად:

#შეიცავს

ასევე არსებობს შესაძლებლობები მომხმარებლის პროგრამებით ახალი ბიბლიოთეკების გაფართოებისა და შესაქმნელად.

გლობალურ ცვლადებს ეთმობა ფიქსირებული ადგილი მეხსიერებაში პროგრამის მთელი ხანგრძლივობის განმავლობაში. ლოკალური ცვლადები ინახება სტეკზე. მათ შორის არის მეხსიერების არეალი დინამიური განაწილებისთვის.

malloc() და free() ფუნქციები გამოიყენება თავისუფალი მეხსიერების დინამიურად გასანაწილებლად. malloc() ფუნქცია გამოყოფს მეხსიერებას, free() ფუნქცია ათავისუფლებს მას. ამ ფუნქციების პროტოტიპები ინახება stdlib.h სათაურის ფაილში და ასე გამოიყურება:

void *malloc(size_t ზომა);

void *free(void *p);

malloc() ფუნქცია აბრუნებს void მაჩვენებელს; სათანადო გამოყენებისთვის, ფუნქციის მნიშვნელობა უნდა გარდაიქმნას მაჩვენებელზე შესაბამისი ტიპისთვის. წარმატების შემთხვევაში, ფუნქცია აბრუნებს მაჩვენებელს ზომის ზომის თავისუფალი მეხსიერების პირველ ბაიტს. თუ არ არის საკმარისი მეხსიერება, დაბრუნდება მნიშვნელობა 0 ცვლადისთვის საჭირო ბაიტების რაოდენობის დასადგენად, გამოიყენეთ ზომაof() ოპერაცია.

ამ ფუნქციების გამოყენების მაგალითი:

#შეიცავს

#შეიცავს

p = (int *) malloc (100 * sizeof(int)); /* მეხსიერების გამოყოფა 100-ზე

მთელი რიცხვები */

printf ("არასაკმარისი მეხსიერება\n");

ამისთვის (i = 0; i< 100; ++i) *(p+i) = i; /* Использование памяти */

ამისთვის (i = 0; i< 100; ++i) printf("%d", *(p++));

უფასო (p);

/* თავისუფალი მეხსიერება */

malloc() მიერ დაბრუნებული მაჩვენებლის გამოყენებამდე უნდა დარწმუნდეთ, რომ საკმარისი მეხსიერებაა (მაჩვენებელი არ არის null).

წინასწარი პროცესორი

C წინასწარი პროცესორი არის პროგრამა, რომელიც ამუშავებს შეყვანას კომპილერში. წინასწარი პროცესორი უყურებს წყაროს პროგრამას და ასრულებს შემდეგ მოქმედებებს: აკავშირებს მითითებულ ფაილებს, ახორციელებს ჩანაცვლებას და ასევე აკონტროლებს კომპილაციის პირობებს. პროგრამის ხაზები, რომლებიც იწყება # სიმბოლოთი, განკუთვნილია წინასწარი პროცესორისთვის. ნებადართულია მხოლოდ ერთი ბრძანების (პრეპროცესორული დირექტივის) ჩაწერა ერთ ხაზზე.

დირექტივა

#define იდენტიფიკატორის ჩანაცვლება

იწვევს დასახელებული იდენტიფიკატორის შეცვლას პროგრამის შემდგომ ტექსტში შემცვლელი ტექსტით (გაითვალისწინეთ მძიმის არარსებობა ამ ბრძანების ბოლოს). არსებითად, ეს დირექტივა შემოაქვს მაკრო განმარტებას, სადაც "იდენტიფიკატორი" არის მაკრო განმარტების სახელი, ხოლო "ჩანაცვლება" არის სიმბოლოების თანმიმდევრობა, რომლითაც წინასწარ პროცესორი ცვლის მითითებულ სახელს, როდესაც ის პოულობს მას პროგრამის ტექსტში. ჩვეულებრივია მაკრო განმარტების სახელი დიდი ასოებით აკრიფოთ.

მოდით შევხედოთ მაგალითებს:

გაითვალისწინეთ, რომ რადგანაც წინასწარი პროცესორი არ ამოწმებს თავსებადობას მაკრო განმარტებების სიმბოლურ სახელებსა და კონტექსტს შორის, რომელშიც ისინი გამოიყენება, რეკომენდებულია ასეთი იდენტიფიკატორების განსაზღვრა არა #define დირექტივით, არამედ const საკვანძო სიტყვის დახმარებით. ტიპის აშკარა მითითება (ეს უფრო მეტად ეხება C+ +-ს):

const int MAX = 25;

(int ტიპი შეიძლება გამოტოვოთ, რადგან ის ნაგულისხმევია).

თუ #define დირექტივა ასე გამოიყურება:

#define identifier (იდენტიფიკატორი, ..., იდენტიფიკატორი) ჩანაცვლება

და არ არის სივრცე პირველ იდენტიფიკატორსა და გახსნის ფრჩხილებს შორის, მაშინ ეს არის მაკრო ჩანაცვლების განმარტება არგუმენტებით. მაგალითად, სტრიქონის შემდეგ, როგორიცაა:

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

განცხადება READ(y); განიხილება ისევე, როგორც scanf("%d",&y);. აქ val არის არგუმენტი და შესრულებულია მაკრო ჩანაცვლება არგუმენტით.

თუ ჩანაცვლებაში არის გრძელი განმარტებები, რომლებიც გრძელდება შემდეგ სტრიქონში, სიმბოლო \ მოთავსებულია შემდეგი გაგრძელების ხაზის ბოლოს.

თქვენ შეგიძლიათ მოათავსოთ ##-ით გამოყოფილი ობიექტები მაკრო განმარტებაში, მაგალითად:

#განსაზღვრა PR(x, y) x##y

ამის შემდეგ, PR(a, 3) დაუძახებს ჩანაცვლებას a3. ან, მაგალითად, მაკრო განსაზღვრება

#განსაზღვრე z(a, b, c, d) a(b##c##d)

გამოიწვევს z(sin, x, +, y) sin(x+y) ჩანაცვლებას.

მაკრო არგუმენტის წინ მოთავსებული # სიმბოლო მიუთითებს, რომ ის გარდაიქმნება სტრინგად. მაგალითად, დირექტივის შემდეგ

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

პროგრამის ტექსტის შემდეგი ფრაგმენტი

გარდაიქმნება ასე:

printf("year""= %d", წელი);

მოდით აღვწეროთ სხვა წინაპროცესორული დირექტივები. #include დირექტივა უკვე ნანახი იყო. მისი გამოყენება შესაძლებელია ორი ფორმით:

#include "ფაილის სახელი"

#შეიცავს<имя файла>

ორივე ბრძანების მოქმედებაა პროგრამაში მითითებული სახელის მქონე ფაილების ჩართვა. პირველი მათგანი ატვირთავს ფაილს მიმდინარე დირექტორიადან ან პრეფიქსის სახით მითითებულ დირექტორიაში. მეორე ბრძანება ეძებს ფაილს პროგრამირების სისტემაში განსაზღვრულ სტანდარტულ ადგილებში. თუ ფაილი, რომლის სახელიც ორმაგი ბრჭყალებით არის დაწერილი, არ მოიძებნება მითითებულ დირექტორიაში, მაშინ ძიება გაგრძელდება #include ბრძანებისთვის მითითებულ ქვედირექტორიებში.<...>. #include დირექტივები შეიძლება იყოს ჩასმული ერთმანეთში.

დირექტივების შემდეგი ჯგუფი საშუალებას გაძლევთ შერჩევით შეადგინოთ პროგრამის ნაწილები. ამ პროცესს პირობითი შედგენა ეწოდება. ამ ჯგუფში შედის დირექტივები #if, #else, #elif, #endif, #ifdef, #ifndef. #if დირექტივის დაწერის ძირითადი ფორმა ასე გამოიყურება:

#if მუდმივი_გამოხატვის ოპერატორების თანმიმდევრობა

აქ მოწმდება მუდმივი გამოხატვის მნიშვნელობა. თუ ეს მართალია, მაშინ შესრულებულია განცხადებების მითითებული თანმიმდევრობა, ხოლო თუ ის მცდარია, მაშინ განცხადებების ეს თანმიმდევრობა გამოტოვებულია.

#else დირექტივის მოქმედება მსგავსია სხვა ბრძანების მოქმედების C ენაზე, მაგალითად:

#თუ მუდმივი_გამოხატვა

განცხადება_მიმდევრობა_2

აქ, თუ მუდმივი გამოხატულება არის true, მაშინ ოპერატორი_sequence_1 შესრულებულია, ხოლო თუ false, ოპერატორი_sequence_2.

#elif დირექტივა ნიშნავს "სხვა თუ" მოქმედებას. მისი გამოყენების ძირითადი ფორმაა:

#თუ მუდმივი_გამოხატვა

განცხადება_მიმდევრობა

#ელიფის მუდმივი_გამოხატვა_1

განცხადება_მიმდევრობა_1

#ელიფის მუდმივი_გამოხატვა_n

განცხადებების_მიმდევრობა_n

ეს ფორმა ჰგავს C ენის კონსტრუქციას: თუ...სხვა თუ...სხვა თუ...

C წინასწარი პროცესორი არის პროგრამა, რომელიც ამუშავებს შეყვანას კომპილერში. წინასწარი პროცესორი უყურებს წყაროს პროგრამას და ასრულებს შემდეგ მოქმედებებს: აკავშირებს მითითებულ ფაილებს, ახორციელებს ჩანაცვლებას და ასევე აკონტროლებს კომპილაციის პირობებს. პროგრამის ხაზები, რომლებიც იწყება # სიმბოლოთი, განკუთვნილია წინასწარი პროცესორისთვის. ნებადართულია მხოლოდ ერთი ბრძანების (პრეპროცესორული დირექტივის) ჩაწერა ერთ ხაზზე.

#ifdef იდენტიფიკატორი

განსაზღვრავს, განსაზღვრულია თუ არა მითითებული იდენტიფიკატორი ამჟამად, ე.ი. შედიოდა თუ არა ის დირექტივებში, როგორიცაა #define. ფორმის სტრიქონი

#ifndef იდენტიფიკატორი

ამოწმებს არის თუ არა მითითებული იდენტიფიკატორი ამჟამად განუსაზღვრელი. ნებისმიერ ამ დირექტივას შეიძლება მოჰყვეს ტექსტის სტრიქონების თვითნებური რაოდენობა, რომელიც შესაძლოა შეიცავდეს #else განცხადებას (#elif არ შეიძლება გამოყენებულ იქნას) და მთავრდება #endif სტრიქონით. თუ შემოწმებული პირობა არის true, მაშინ ყველა ხაზი #else-სა და #endif-ს შორის იგნორირებულია, ხოლო თუ false, მაშინ ხაზები check-სა და #else-ს შორის (თუ არ არის სიტყვა #else, მაშინ #endif). #if და #ifndef დირექტივები შეიძლება იყოს ჩადებული ერთმანეთში.

დირექტივის ნახვა

#undef იდენტიფიკატორი

იწვევს მითითებული იდენტიფიკატორის განუსაზღვრელად მიჩნევას, ე.ი. ჩანაცვლებას არ ექვემდებარება.

მოდით შევხედოთ მაგალითებს. შემდეგი სამი დირექტივა:

შეამოწმეთ არის თუ არა განსაზღვრული WRITE იდენტიფიკატორი (ანუ იყო თუ არა ბრძანება, როგორიცაა #define WRITE...), და თუ ასეა, მაშინ WRITE სახელი იწყება განიხილება განუსაზღვრელი, ე.ი. ჩანაცვლებას არ ექვემდებარება.

დირექტივები

#define WRITE fprintf

ამოწმებს არის თუ არა WRITE იდენტიფიკატორი განუსაზღვრელი, და თუ ასეა, WRITE იდენტიფიკატორი განისაზღვრება fprintf სახელის ნაცვლად.

#error დირექტივა დაწერილია შემდეგი ფორმით:

#error error_message

თუ ეს ხდება პროგრამის ტექსტში, კომპილაცია ჩერდება და ეკრანზე გამოჩნდება შეცდომის შეტყობინება. ეს ბრძანება ძირითადად გამოიყენება გამართვის ფაზაში. გაითვალისწინეთ, რომ შეცდომის შესახებ შეტყობინება არ არის საჭირო ორმაგი ბრჭყალებში ჩასმა.

#line დირექტივა გამიზნულია C პროგრამირების სისტემაში განსაზღვრული _LINE_ და _FILE_ ცვლადების მნიშვნელობების შესაცვლელად. ცვლადი _LINE_ შეიცავს ამჟამად შესრულებული პროგრამის ხაზის ნომერს. _FILE_ იდენტიფიკატორი არის სტრიქონის მითითება შედგენილი პროგრამის სახელით. #line დირექტივა იწერება შემდეგნაირად:

#ხაზის ნომერი "file_name"

აქ ნომერი არის ნებისმიერი დადებითი მთელი რიცხვი, რომელიც მიენიჭება _LINE_ ცვლადს, file_name არის არასავალდებულო პარამეტრი, რომელიც არღვევს _FILE_-ის მნიშვნელობას.

#pragma დირექტივა საშუალებას გაძლევთ გადასცეთ გარკვეული ინსტრუქციები შემდგენელს. მაგალითად, ხაზი

მიუთითებს, რომ C პროგრამა შეიცავს ასამბლეის ენის სტრიქონებს. მაგალითად:

მოდით შევხედოთ რამდენიმე გლობალურ იდენტიფიკატორს ან მაკროსახელს (მაკრო განსაზღვრების სახელები). ხუთი ასეთი სახელია განსაზღვრული: _LINE_, _FILE_, _DATE_, _TIME_, _STDC_. ორი მათგანი (_LINE_ და _FILE_) უკვე აღწერილია ზემოთ. _DATE_ იდენტიფიკატორი განსაზღვრავს სტრიქონს, რომელიც ინახავს წყაროს ფაილის ობიექტურ კოდში გადათარგმნის თარიღს. _TIME_ იდენტიფიკატორი განსაზღვრავს სტრიქონს, რომელიც ინახავს დროს, როდესაც წყარო ფაილი გადაკეთდა ობიექტურ კოდში. _STDC_ მაკროს აქვს 1 მნიშვნელობა, თუ გამოიყენება სტანდარტული განსაზღვრული მაკრო სახელები. წინააღმდეგ შემთხვევაში ეს ცვლადი არ იქნება განსაზღვრული.



რაიმე შეკითხვა?

შეატყობინეთ შეცდომას

ტექსტი, რომელიც გაეგზავნება ჩვენს რედაქტორებს: