সি কোড যা লুপ বা শর্তসাপেক্ষ বিবৃতি ছাড়াই 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.