সি কোড যা লুপ বা শর্তসাপেক্ষ বিবৃতি ছাড়াই 1 থেকে 1000 পর্যন্ত মুদ্রণ করে?


148

আমি এমন Cকোড পেয়েছি যা লুপ বা শর্ত ছাড়াই 1 থেকে 1000 পর্যন্ত মুদ্রণ করে : তবে কীভাবে এটি কাজ করে তা আমি বুঝতে পারি না। কোডটি দিয়ে কেউ কি প্রতিটি লাইন ব্যাখ্যা করতে পারে?

#include <stdio.h>
#include <stdlib.h>

void main(int j) {
  printf("%d\n", j);
  (&main + (&exit - &main)*(j/1000))(j+1);
}

1
আপনি সি হিসাবে বা সি ++ হিসাবে সংকলন করছেন? আপনি কি ত্রুটি দেখতে পাচ্ছেন? আপনি mainসি ++ এ কল করতে পারবেন না ।
— নিনজালজ

@ নিনজালজ আমি একটি সি ++ প্রকল্প তৈরি করেছি এবং কোডটি অনুলিপি করে দিয়েছি: ত্রুটিটি হ'ল অবৈধ, বাম অপারেণ্ডে টাইপ রয়েছে 'অকার্যকর (__cdecl *) (ইনট)' এবং এক্সপ্রেশন অবশ্যই একটি সম্পূর্ণ অবজেক্ট টাইপের পয়েন্টার হতে হবে
— ob_dev

1
@ নিনজালজ এই কোডটি আদর্শের.অর্গ নিয়ে কাজ করছে তবে ভিজ্যুয়াল স্টুডিওতে নয় আদর্শ
— এমটিজে 1

@ ওসামা একই, তবে বুঝতে আরও কিছুটা কঠিন: আদর্শআন.২০.আইটিএক্সএম আপনার স্বাগত। :)
— চিহ্নিত করুন

2
আমি এই লাইন থেকে সমস্ত 'এবং' অক্ষর মুছে ফেলেছি (& মূল + (& প্রস্থান - & মূল) * (জে / 1000)) (জে + 1); এবং এই কোডটি এখনও কাজ করে।
— ob_dev

উত্তর:


264

এর মতো কোড কখনও লিখবেন না।


এর জন্য j<1000, j/1000শূন্য (পূর্ণসংখ্যা বিভাগ)। তাই:

(&main + (&exit - &main)*(j/1000))(j+1);

সমান:

(&main + (&exit - &main)*0)(j+1);

যা হলো:

(&main)(j+1);

কোনটি আহ্বান mainসঙ্গে j+1।

যদি j == 1000, তবে একই লাইনগুলি বেরিয়ে আসে:

(&main + (&exit - &main)*1)(j+1);

যা ফুটতে থাকে

(&exit)(j+1);

যা হয় exit(j+1)এবং প্রোগ্রামটি ছেড়ে যায়।


(&exit)(j+1)এবং exit(j+1)মূলত একই জিনিস - C99 ing6.3.2.1 / 4 উদ্ধৃত:

একটি ফাংশন ডিজাইনার একটি এক্সপ্রেশন যা ফাংশন টাইপ আছে। এটি যখন আকারের অপারেটরের অপারেন্ড বা ইউনিারি অ্যান্ড অপারেটর ব্যতীত , " ফাংশন রিটার্নিং টাইপ " টাইপযুক্ত একটি ফাংশন ডিজাইনার এমন একটি অভিব্যক্তিতে রূপান্তরিত হয় যা " ফাংশন রিটার্নিং টাইপের পয়েন্টার " টাইপযুক্ত একটি এক্সপ্রেশনতে রূপান্তরিত হয় ।

exitএকটি ফাংশন ডিজাইনার। এমনকি অবিচ্ছিন্ন &ঠিকানা-অপারেটর ছাড়াও , এটি কাজ করার জন্য পয়েন্টার হিসাবে বিবেচনা করা হয়। ( &ন্যায়সঙ্গত এটি স্পষ্ট করে তোলে makes)

এবং ফাংশন কলগুলি §6.5.2.2 / 1 এবং নিম্নলিখিতটিতে বর্ণিত হয়েছে:

অভিব্যক্তি যা ডাকা ফাংশনটিকে বোঝায় সেগুলিতে ফাংশন করতে টাইপ পয়েন্টার থাকবে অকার্যকর টাইপ ব্যতীত অন্য কোনও অবজেক্ট টাইপ ফিরিয়ে আনতে ।

সুতরাং exit(j+1)ফাংশন প্রকারের পয়েন্টার-টু-ফাংশন ধরণের স্বয়ংক্রিয় রূপান্তরকরণের কারণে কাজ করে এবং পয়েন্টার-টু-ফাংশন ধরণের (&exit)(j+1)স্পষ্ট রূপান্তরকরণের পাশাপাশি কাজ করে।

বলা হচ্ছে, উপরোক্ত কোডটি মেনে চলছে না ( mainহয় দুটি আর্গুমেন্ট গ্রহণ করে বা &exit - &mainমোটেও কিছুই হয় না), এবং আমি বিশ্বাস করি, §§..6. / / ৯ অনুসারে অপরিবর্তিত:

যখন দুটি পয়েন্টার বিয়োগ করা হয়, উভয়ই একই অ্যারে অবজেক্টের উপাদানগুলিকে নির্দেশ করবে বা অ্যারে অবজেক্টের শেষ উপাদানটির একটিতে; ...

সংযোজনটি (&main + ...)নিজেই বৈধ হবে এবং যুক্ত পরিমাণটি শূন্য হলে এটি ব্যবহার করা যেতে পারে , যেহেতু .5§..6..6 / says বলেছেন:

এই অপারেটরগুলির উদ্দেশ্যে, কোনও বস্তুর পয়েন্টার যা অ্যারের উপাদান নয়, বিন্দুর সাথে তার দৈর্ঘ্যের অ্যারের প্রথম এলিমেন্টের সাথে তার উপাদান ধরণের হিসাবে একই আচরণ করে।

সুতরাং শূন্য যুক্ত &mainকরা ঠিক হবে (তবে বেশি ব্যবহার নয়)।


4
foo(arg)এবং (&foo)(arg)সমতুল্য, তারা যুক্তিকে যুক্তি দিয়ে ফু বলে with newty.de/fpt/fpt.html ফাংশন পয়েন্টার সম্পর্কে একটি আকর্ষণীয় পৃষ্ঠা।
— মাদুর

1
@Krishnabhadra: প্রথম ক্ষেত্রে, foo, একটি পয়েন্টার &fooযে পয়েন্টার ঠিকানা। দ্বিতীয় ক্ষেত্রে, fooএকটি অ্যারে, এবং &fooফু এর সমতুল্য।
— মাদুর

8
অহেতুক জটিল, কমপক্ষে সি 99 এর জন্য:((void(*[])()){main, exit})[j / 1000](j + 1);
— প্রতি জোহানসন

1
&fooএটি fooযখন অ্যারে আসে তখন একই হয় না । &fooঅ্যারের fooএকটি পয়েন্টার, প্রথম উপাদান একটি পয়েন্টার। যদিও তাদের একই মান রয়েছে। ফাংশনগুলির জন্য, funএবং &funউভয়ই ফাংশনের পয়েন্টার।
— প্রতি জোহানসন

1
এফওয়াইআই, আপনি যদি উপরে উল্লিখিত অন্যান্য প্রশ্নের প্রাসঙ্গিক উত্তরটি দেখেন তবে আপনি দেখতে পাচ্ছেন যে বাস্তবে কমরফ্যান্ট সি 99 রয়েছে। ভীতিজনক, তবে সত্য।
— ড্যানিয়েল প্রাইডেন

41

এটি পুনরাবৃত্তি, পয়েন্টার পাটিগণিত ব্যবহার করে এবং পূর্ণসংখ্যা বিভাগের বৃত্তাকারী আচরণটি ব্যবহার করে।

এই j/1000শব্দটি সকলের জন্য 0-এ পরিণত হয় j < 1000; একবারে j1000 পৌঁছে, এটি 1 এ মূল্যায়ন করে।

এখন যদি আপনার হয় a + (b - a) * n, যেখানে n0 বা 1 হয়, আপনি aযদি n == 0, এবং bযদি শেষ করেন n == 1। ব্যবহার &main(এর ঠিকানা main()) এবং &exitজন্য aএবং bশব্দটি (&main + (&exit - &main) * (j/1000))আয় &mainযখন j1000 নীচে, &exitঅন্যথায়। ফলস্বরূপ ফাংশন পয়েন্টারটি পরে আর্গুমেন্টকে খাওয়ানো হয় j+1।

এই পুরোটি পুনরাবৃত্ত আচরণের ফলাফল তৈরি করে: যখন jএটি 1000 এর নীচে থাকে তখন mainনিজেকে পুনরাবৃত্তভাবে ডাকে; যখন j1000 এ পৌঁছায়, exitপরিবর্তে এটি কল করে 1001 প্রস্থান কোড (যা একধরণের নোংরা, তবে কাজ করে) দিয়ে প্রোগ্রামটি প্রস্থান করে।


1
উত্তম উত্তর, তবে একটি সন্দেহ..এই প্রস্থান কোড 1001 সহ প্রধান প্রস্থানটি কীভাবে? মেইন কিছুই ফিরিয়ে দিচ্ছে না ... কোনও ডিফল্ট ফেরতের মান?
— কৃষ্ণভদ্র

2
যখন জে 1000 এ পৌঁছায়, মূলটি আর নিজের মধ্যে পুনরাবৃত্তি হয় না; পরিবর্তে, এটি libc ফাংশন বলে exit, যা প্রস্থান কোডটিকে তার আর্গুমেন্ট হিসাবে গ্রহণ করে এবং ভাল, বর্তমান প্রক্রিয়াটি প্রস্থান করে। এই মুহুর্তে, জে 1000, সুতরাং জ + 1 সমান 1001, যা প্রস্থান কোড হয়ে যায়।
— tdammers
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.