#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
int begin()
{
printf("Ha HA see how it is?? ");
}
এটি কি পরোক্ষভাবে কল করে main
? কিভাবে?
#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
int begin()
{
printf("Ha HA see how it is?? ");
}
এটি কি পরোক্ষভাবে কল করে main
? কিভাবে?
উত্তর:
সি ভাষা কার্যকরকরণ পরিবেশকে দুটি বিভাগে সংজ্ঞায়িত করে: ফ্রিস্ট্যান্ডিং এবং হোস্ট করা । উভয় সম্পাদনের পরিবেশে প্রোগ্রাম দ্বারা প্রারম্ভের জন্য পরিবেশ দ্বারা একটি ফাংশন ডেকে আনা হয়।
একটি ফ্রিস্ট্যান্ডিং এনভায়রনমেন্ট প্রোগ্রামে স্টার্টআপ ফাংশনটি বাস্তবায়ন সংজ্ঞায়িত করা যায় যদিও এটি হোস্ট করা পরিবেশে হওয়া উচিত main
। সি তে কোনও প্রোগ্রাম নির্ধারিত পরিবেশগুলিতে প্রোগ্রাম স্টার্টআপ ফাংশন ব্যতীত চলতে পারে না।
আপনার ক্ষেত্রে, main
প্রিপ্রোসেসর সংজ্ঞা দ্বারা গোপন করা হয়। আরও begin()
প্রসারিত হবে decode(a,n,i,m,a,t,e)
যা প্রসারিত হবে main
।
int begin() -> int decode(a,n,i,m,a,t,e)() -> int m##a##i##n() -> int main()
decode(s,t,u,m,p,e,d)
7 পরামিতি সহ একটি প্যারামিটারাইজড ম্যাক্রো। এই ম্যাক্রোর প্রতিস্থাপনের তালিকাটি m##s##u##t
। m, s, u
এবং প্রতিস্থাপন তালিকায় ব্যবহৃত t
4 ম , 1 ম , 3 য় আর 2 তম প্যারামিটার।
s, t, u, m, p, e, d
1 2 3 4 5 6 7
বাকীগুলি কোনও কাজে আসে না ( কেবল অবলীলায় )। আর্গুমেন্টটি decode
" এ , এন , আই , এম , এ, টি, ই" হয় তাই শনাক্তকারী m, s, u
এবং t
যুক্তি m, a, i
এবং n
যথাক্রমে প্রতিস্থাপন করা হয়।
m --> m
s --> a
u --> i
t --> n
_start()
। বা আরও নিম্ন-স্তরের আমি আমার প্রোগ্রামের শুরুটি ঠিক ঠিক ঠিকানা ঠিকঠাক করে চেষ্টা করতে পারি যে বুটের পরে আইপি সেট করা আছে। main()
সি স্ট্যান্ডার্ড লাইব্রেরি হয় । সি নিজেই এ নিয়ে কোনও বিধিনিষেধ আরোপ করে না।
decode(a,n,i,m,a,t,e)
হয়ে m##a##i##n
? এটি চরিত্রগুলি প্রতিস্থাপন করে? আপনি কি decode
ফাংশনের ডকুমেন্টেশনের লিঙ্ক সরবরাহ করতে পারেন ? ধন্যবাদ
begin
পরিবর্তে সংজ্ঞায়িত করা হয়েছে decode(a,n,i,m,a,t,e)
যা আগে সংজ্ঞায়িত করা হয়েছে। এই ফাংশনটি আর্গুমেন্ট গ্রহণ s,t,u,m,p,e,d
করে এবং এই ফর্মটিতে তাদের সংমিশ্রিত করে m##s##u##t
( ##
যার অর্থ কনকানেটেট)। অর্থাৎ এটি পি, ই এবং ডি এর মান অগ্রাহ্য করে। আপনি decode
s = a, t = n, u = i, m = m দিয়ে "কল" করার সাথে সাথে এটি কার্যকরভাবে প্রতিস্থাপন begin
করে main
।
ব্যবহারের চেষ্টা করুন gcc -E source.c
, আউটপুট এর সাথে শেষ হয়:
int main()
{
printf("Ha HA see how it is?? ");
}
সুতরাং একটি main()
ফাংশন আসলে প্রিপ্রসেসর দ্বারা উত্পাদিত হয়।
ম্যাক্রো প্রসারণের কারণে প্রশ্নযুক্ত প্রোগ্রামটি কল করেmain()
, তবে আপনার অনুমান ত্রুটিযুক্ত - এটিতে কোনও কল main()
করতে হবে না!
কড়া কথায় বলতে গেলে আপনার কাছে একটি সি প্রোগ্রাম থাকতে পারে এবং এটি কোনও main
চিহ্ন না রেখে সংকলন করতে সক্ষম হতে পারে । main
এটি এমন একটি জিনিস যা c library
এটির নিজের সূচনাটি শেষ করার পরেও ঝাঁপিয়ে পড়ার প্রত্যাশা করে। সাধারণত আপনি main
libc প্রতীক হিসাবে পরিচিত হিসাবে ঝাঁপ দাও _start
। কোনও বৈধ প্রোগ্রাম থাকা সর্বদা সম্ভব, এটি কেবল প্রধান না করেই সমাবেশ পরিচালনা করে। এক নজর দেখে নাও:
/* This must be compiled with the flag -nostdlib because otherwise the
* linker will complain about multiple definitions of the symbol _start
* (one here and one in glibc) and a missing reference to symbol main
* (that the libc expects to be linked against).
*/
void
_start ()
{
/* calling the write system call, with the arguments in this order:
* 1. the stdout file descriptor
* 2. the buffer we want to print (Here it's just a string literal).
* 3. the amount of bytes we want to write.
*/
asm ("int $0x80"::"a"(4), "b"(1), "c"("Hello world!\n"), "d"(13));
asm ("int $0x80"::"a"(1), "b"(0)); /* calling exit syscall, with the argument to be 0 */
}
উপরেরটি দিয়ে এগুলি সংকলন করুন gcc -nostdlib without_main.c
এবং Hello World!
কেবল ইনলাইন অ্যাসেমব্লিতে সিস্টেম কল (বিঘ্নিত) জারি করে এটি পর্দায় মুদ্রণযোগ্য দেখুন।
এই নির্দিষ্ট সমস্যা সম্পর্কে আরও তথ্যের জন্য, ksplice ব্লগটি দেখুন
আর একটি আকর্ষণীয় বিষয় হ'ল এটি হ'ল আপনার এমন একটি প্রোগ্রামও থাকতে main
পারে যা সি ফাংশনের সাথে প্রতীক না রেখে সংকলন করে। উদাহরণস্বরূপ, আপনার একটি খুব কার্যকর সি প্রোগ্রাম হিসাবে নিম্নলিখিতগুলি থাকতে পারে, যা সতর্কতা স্তরটি আপ করার সময় কেবল সংকলকটিকে আরও সজ্জিত করে।
/* These values are extracted from the decimal representation of the instructions
* of a hello world program written in asm, that gdb provides.
*/
const int main[] = {
-443987883, 440, 113408, -1922629632,
4149, 899584, 84869120, 15544,
266023168, 1818576901, 1461743468, 1684828783,
-1017312735
};
অ্যারের মানগুলি বাইট যা স্ক্রিনে হ্যালো ওয়ার্ল্ড প্রিন্ট করার জন্য প্রয়োজনীয় নির্দেশাবলীর সাথে সামঞ্জস্য করে। এই সুনির্দিষ্ট প্রোগ্রামটি কীভাবে কাজ করে তার আরও বিশদ বিবরণের জন্য, এই ব্লগ পোস্টটি একবার দেখুন , আমি এখানে এটি প্রথমও পড়েছি।
আমি এই প্রোগ্রামগুলি সম্পর্কে একটি চূড়ান্ত নোটিশ করতে চাই। আমি জানি না যে তারা সি ভাষার স্পেসিফিকেশন অনুযায়ী বৈধ সি প্রোগ্রাম হিসাবে নিবন্ধভুক্ত কিনা, তবে এগুলি সংকলন করা এবং সেগুলি চালানো অবশ্যই খুব সম্ভব, এমনকি যদি তারা স্পেসিফিকেশনটি নিজেই লঙ্ঘন করে।
_start
একটি সংজ্ঞায়িত স্ট্যান্ডার্ডের অংশের নাম , বা এটি কেবল বাস্তবায়ন-নির্দিষ্ট? অবশ্যই আপনার "অ্যারের হিসাবে প্রধান" আর্কিটেকচার-নির্দিষ্ট। এছাড়াও গুরুত্বপূর্ণ, আপনার "প্রধান হিসাবে একটি অ্যারের" কৌশলটি সুরক্ষার বিধিনিষেধের কারণে রান সময়ে ব্যর্থ হওয়া অযৌক্তিক হবে না (যদিও আপনি const
কোয়ালিফায়ারটি ব্যবহার না করেন তবে এটি আরও বেশি সম্ভাবনাযুক্ত হতে পারে , এবং এখনও অনেক সিস্টেম এটির অনুমতি দিবে)।
_start
ইএলএফ স্ট্যান্ডার্ডে নেই, যদিও এএমডি ps৪ পিএসএবিআইতে ৩.৪ প্রক্রিয়া_start
শুরুর দিকে উল্লেখ রয়েছে । আনুষ্ঠানিকভাবে, ইএলএফ কেবলমাত্র ইএলএফ শিরোনামের ঠিকানা সম্পর্কে জানে , বাস্তবায়নটি বেছে নেওয়া একটি নাম। e_entry
_start
const
কিছুটা গুরুত্বপূর্ণ হবে না - সেই বাইনারি এক্সিকিউটেবল ফাইলের প্রতীক নামটি main
। বেশিও না, কমও না. const
একটি সি কন্সট্রাক্ট যার অর্থ কার্যকর করার সময় কিছুই হয় না।
কেউ যাদুকরের মতো অভিনয় করার চেষ্টা করছেন। সে মনে করে যে সে আমাদের প্রতারিত করতে পারে। তবে আমরা সকলেই জানি, সি প্রোগ্রামের প্রয়োগটি শুরু হয় main()
।
int begin()
সঙ্গে প্রতিস্থাপন করা হবে decode(a,n,i,m,a,t,e)
প্রাক প্রসেসর পর্যায় এক পাস দ্বারা। তারপরে আবার decode(a,n,i,m,a,t,e)
m ## a ## i ## n দিয়ে প্রতিস্থাপন করা হবে। ম্যাক্রো কলের অবস্থানগত সমিতি হিসাবে s
, চরিত্রের একটি মান থাকবে a
। একইভাবে, u
'i' t
দ্বারা প্রতিস্থাপিত হবে এবং 'এন' দ্বারা প্রতিস্থাপিত হবে। এবং, এইভাবে, m##s##u##t
হয়ে যাবেmain
সম্পর্কিত, ##
ম্যাক্রো প্রসারণের প্রতীক, এটি প্রাকপ্রসেসিং অপারেটর এবং এটি টোকন পেস্টিং সম্পাদন করে। যখন কোনও ম্যাক্রো প্রসারিত হয়, প্রতিটি '##' অপারেটরের উভয় পাশের দুটি টোকেনকে একক টোকনে একত্রিত করা হয়, যা ম্যাক্রো প্রসারণে '##' এবং দুটি মূল টোকেনকে প্রতিস্থাপন করে।
আপনি যদি আমাকে বিশ্বাস না করেন তবে আপনি -E
পতাকা সহ আপনার কোডটি সংকলন করতে পারেন । এটি প্রিপ্রোসেসিংয়ের পরে সংকলন প্রক্রিয়া বন্ধ করবে এবং আপনি টোকেন আটকানোর ফলাফল দেখতে পাবেন।
gcc -E FILENAME.c
decode(a,b,c,d,[...])
প্রথম চারটি আর্গুমেন্ট পরিবর্তন করে এবং ক্রমে একটি নতুন সনাক্তকারী পেতে তাদের সাথে যোগ দেয় dacb
। (বাকি তিনটি যুক্তি উপেক্ষা করা হয়)) উদাহরণস্বরূপ, decode(a,n,i,m,[...])
শনাক্তকারী দেয় main
। নোট করুন যে এটি begin
ম্যাক্রো হিসাবে সংজ্ঞায়িত হয়েছে।
সুতরাং, begin
ম্যাক্রো কেবল হিসাবে সংজ্ঞায়িত করা হয় main
।
আপনার উদাহরণে, main()
ফাংশনটি আসলে উপস্থিত রয়েছে, কারণ begin
একটি ম্যাক্রো যা সংকলকটি decode
ম্যাক্রোর সাথে প্রতিস্থাপন করে যা পরিবর্তিতভাবে এম ## এস ## ইউ ## টি অভিব্যক্তি দ্বারা প্রতিস্থাপিত হয়। ম্যাক্রো সম্প্রসারণ ব্যবহার ##
, আপনি শব্দ পৌঁছবে main
থেকে decode
। এটি একটি ট্রেস:
begin --> decode(a,n,i,m,a,t,e) --> m##parameter1##parameter3##parameter2 ---> main
এটি থাকা মাত্র একটি কৌশল main()
, তবে main()
প্রোগ্রামিংয়ের প্রবেশ ফাংশনের জন্য নাম ব্যবহার করা সি প্রোগ্রামিং ভাষায় প্রয়োজন হয় না। এটি আপনার অপারেটিং সিস্টেম এবং এর অন্যতম সরঞ্জাম হিসাবে লিঙ্কারের উপর নির্ভর করে।
উইন্ডোজ, আপনি সবসময় ব্যবহার করবেন না main()
, কিন্তু বরং WinMain
বাwWinMain
, যদিও আপনি ব্যবহার করতে পারেন main()
, এমনকি Microsoft এর টুলচেইন সঙ্গে । লিনাক্সে, কেউ ব্যবহার করতে পারেন _start
।
এন্ট্রি পয়েন্ট সেট করার জন্য এটি অপারেটিং সিস্টেমের সরঞ্জাম হিসাবে লিঙ্কারের উপর নির্ভর করে, ভাষাটি নয়। আপনি আমাদের নিজস্ব এন্ট্রি পয়েন্ট এমনকি সেট করতে পারেন, এবং আপনি একটি লাইব্রেরি তৈরি করতে পারেন যা কার্যকরও হয় !
main()
সি প্রোগ্রামিং ভাষার সাথে ফাংশনকে আবদ্ধ করে, যা সঠিক নয়।