সি-এ অকার্যকর পয়েন্টারের জন্য পয়েন্টার গাণিতিক


176

যখন একটি বিশেষ ধরনের একটি পয়েন্টার (বলুন int, char, float, ..) বৃদ্ধি করা হয়, এর মান যে ডাটা টাইপ মাপ বৃদ্ধি করা হয়। voidআকারের ডেটাতে নির্দেশকারী একটি পয়েন্টার xযদি বাড়ানো হয় তবে এটি কীভাবে xএগিয়ে বাইটে পয়েন্ট পাবেন ? সংকলক xপয়েন্টারের মান যুক্ত করতে কীভাবে জানতে পারে ?



3
প্রশ্নটি মনে হচ্ছে যদিও এটি ধরে নেওয়া হয়েছে যে সংকলক (/ রান-টাইম) জানে যে পয়েন্টারটি কোন ধরণের অবজেক্টে সেট করা হয়েছিল এবং এটি পয়েন্টারের সাথে তার আকার যুক্ত করে। এটি একটি সম্পূর্ণ ভুল ধারণা: এটি কেবল ঠিকানাটি জানে।
পিজেট্রাইল 21

2
" voidআকারের ডেটাতে নির্দেশকারী একটি পয়েন্টার xযদি বাড়ানো হয় তবে এটি কীভাবে xএগিয়ে বাইটে পয়েন্ট পাবেন ?" এটা হয় না। যেসব লোকের কাছে এ জাতীয় প্রশ্ন রয়েছে তারা কেন জিজ্ঞাসার আগে তাদের পরীক্ষা করতে পারবেন না - হ্যাঁ, অন্তত সর্বনিম্ন যেখানে তারা এটি যাচাই করে যা এটি আসলে সংকলন করে কিনা তা যাচাই করে। -1, এটি +100 এবং -0 পেয়েছে বিশ্বাস করতে পারে না।
আন্ডারস্কোর_ডে

উত্তর:


287

চূড়ান্ত উপসংহার: A এর গাণিতিকগুলি সি এবং সি ++ উভয় void*ক্ষেত্রেই অবৈধ

জিসিসি এটিকে এক্সটেনশান হিসাবে অনুমতি দেয়, গাণিতিকটি void- এবং ফাংশন-পয়েন্টারগুলি দেখুন (নোট করুন যে এই বিভাগটি ম্যানুয়ালটির "সি এক্সটেনশান" অধ্যায়ের অংশ)। ঝনঝন এবং আইসিসি সম্ভবত void*জিসিসির সাথে সামঞ্জস্যের উদ্দেশ্যে পাটিগণিতের অনুমতি দেয় । অন্যান্য সংকলক (যেমন এমএসভিসি) গাণিতিকটিকে নিষ্ক্রিয় করে void*, এবং -pedantic-errorsপতাকাটি নির্দিষ্ট করা থাকলে, বা -Werror-pointer-arithপতাকাটি নির্দিষ্ট করা থাকলে (এই কোডটি কার্যকর যদি আপনার কোড বেসটি এমএসভিসির সাথেও সংকলন করতে হবে) এই জিসিসি তা অস্বীকার করে ।

সি স্ট্যান্ডার্ড কথা বলে

এন 1256 খসড়া থেকে উদ্ধৃতি নেওয়া হয়েছে।

সংযোজন অপারেশনটির স্ট্যান্ডার্ডের বিবরণে বলা হয়েছে:

..৫.-2-২: অতিরিক্ত হিসাবে, উভয় অপারেন্ডের গাণিতিক টাইপ থাকবে, বা একটি অপারেন্ড কোনও অবজেক্ট টাইপের পয়েন্টার এবং অন্যটির পূর্ণসংখ্যার ধরণ থাকবে।

সুতরাং, এখানে প্রশ্নটি void*একটি "অবজেক্ট টাইপ" এর পয়েন্টার কিনা , বা সমতুল্য, void"অবজেক্ট টাইপ" কিনা । "অবজেক্ট টাইপ" এর সংজ্ঞাটি হ'ল:

.2.২.৫.১: প্রকারগুলি অবজেক্টের ধরণগুলিতে বিভক্ত হয় ( ধরণগুলি সম্পূর্ণরূপে বর্ণনা করে এমন প্রকারগুলি), ফাংশন ধরণের ( ফাংশনগুলিতে বর্ণিত প্রকারগুলি) এবং অসম্পূর্ণ প্রকারগুলি (যে ধরণের বিষয়গুলি বর্ণনা করে তবে আকারগুলি নির্ধারণের জন্য প্রয়োজনীয় তথ্যের অভাব রয়েছে)।

এবং মানটি এইভাবে সংজ্ঞায়িত voidকরে:

.2.২.৫-১৯: টাইপটিতে voidমানগুলির একটি খালি সেট থাকে; এটি একটি অসম্পূর্ণ প্রকার যা সম্পূর্ণ করা যায় না।

যেহেতু voidএকটি অসম্পূর্ণ প্রকার, তাই এটি কোনও বস্তুর প্রকার নয়। সুতরাং এটি কোনও অতিরিক্ত ক্রিয়াকলাপের জন্য বৈধ অপারেন্ড নয়।

অতএব আপনি একটি voidপয়েন্টারের উপর পয়েন্টার গাণিতিক সম্পাদন করতে পারবেন না ।

মন্তব্য

মূলত, void*সি-স্ট্যান্ডার্ডের এই বিভাগগুলির কারণে, এটি গণিতের অনুমতি দেওয়া হয়েছিল বলে মনে করা হয়েছিল:

.2.২.৫-২7: অকার্যকর হওয়ার জন্য একটি পয়েন্টারের একটি চরিত্রের ধরণের পয়েন্টার হিসাবে একই উপস্থাপনা এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে।

যাহোক,

একই প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তাগুলি হ'ল ফাংশনগুলিতে আর্গুমেন্ট, ফাংশন থেকে মানগুলি ফেরত দেওয়া এবং ইউনিয়নের সদস্য হিসাবে আদান প্রদানের বোঝা।

এর অর্থ এই যে তাই printf("%s", x)কিনা একই অর্থ xটাইপ হয়েছে char*বা void*, কিন্তু এটা মানে এই নয় যে আপনি একটি উপর গাণিতিক কি করতে পারেন void*

সম্পাদকের দ্রষ্টব্য: এই উত্তরটি চূড়ান্ত উপসংহার প্রতিফলিত করতে সম্পাদিত হয়েছে।


7
C99 স্ট্যান্ডার্ড থেকে: (.5..5..2.২) অতিরিক্ত হিসাবে উভয় অপারেন্ডের গাণিতিক টাইপ থাকবে, অথবা একটি অপারেন্ড কোনও অবজেক্ট টাইপের পয়েন্টার এবং অন্যটির পূর্ণসংখ্যার ধরণ থাকবে। (.2.২.৫.১৯) অকার্যকর ধরণের মানগুলির একটি খালি সেট থাকে; এটি একটি অসম্পূর্ণ প্রকার যা সম্পূর্ণ করা যায় না। আমি মনে করি এটি স্পষ্ট করে দেয় যে void*পয়েন্টার গাণিতিক অনুমোদিত নয়। জিসিসির একটি এক্সটেনশন রয়েছে যা এটি করতে দেয়।
কাজ

1
আপনি যদি নিজের উত্তরটি কার্যকর মনে করেন না, আপনি কেবল এটি মুছতে পারেন।
ক্যাফে

1
এই উত্তরটি ভুল প্রমাণিত হওয়া সত্ত্বেও এটি কার্যকর ছিল কারণ এতে চূড়ান্ত প্রমাণ রয়েছে যে শূন্যপদগুলি গাণিতিকের জন্য নয়।
বেন ফ্লেইন

1
এটি একটি ভাল উত্তর, এটির সঠিক উপসংহার এবং প্রয়োজনীয় উদ্ধৃতি রয়েছে, কিন্তু এই প্রশ্নে আসা লোকেরা ভুল সিদ্ধান্তে এসেছিল কারণ তারা উত্তরের নীচে পড়ে না। এটিকে আরও সুস্পষ্ট করার জন্য আমি এটি সম্পাদনা করেছি
ডায়রিচ এপ্প

1
ঝনঝন এবং আইসিসি void*পাটিগণিতের অনুমতি দেয় না (কমপক্ষে ডিফল্ট হিসাবে)।
সের্গে পোডোব্রি

61

পয়েন্টারগুলিতে পয়েন্টার গাণিতিক অনুমোদিত নয় void*


16
+1 পয়েন্টার গাণিতিক কেবলমাত্র (সম্পূর্ণ) অবজেক্টের ধরণের পয়েন্টারগুলির জন্য সংজ্ঞায়িত হয় । voidএকটি অসম্পূর্ণ প্রকার যা সংজ্ঞা দিয়ে কখনই শেষ করা যায় না।
স্কট 15

1
@ স্কট: হুবহু তদুপরি, পয়েন্টার গাণিতিকটি কেবলমাত্র একটি অ্যারে অবজেক্টের একটি উপাদানকে নির্দেশক হিসাবে সংজ্ঞায়িত করা হয় এবং কেবলমাত্র অপারেশনের ফলাফল যদি একই অ্যারেতে থাকা কোনও উপাদানের পয়েন্টার বা সেই অ্যারের শেষ উপাদানটির একটি অতীত হয়। যদি এই শর্তগুলি পূরণ না হয় তবে এটি অপরিবর্তিত আচরণ। (সি 99 স্ট্যান্ডার্ড 6.5.6.8 থেকে)
কাজ

1
স্পষ্টতই এটি জিসিসি 7.3.0 এর সাথে হয় না। সংকলক পি + 1024 গ্রহণ করে, যেখানে পি শূন্য *। এবং ফলাফলটি ((চর *) পি) + 1024
zzz777

@ zzz777 এটি একটি জিসিসি এক্সটেনশন, শীর্ষে ভোট দেওয়া উত্তরের লিঙ্কটি দেখুন।
রুসলান

19

এটিকে একটি চর পয়েন্টারে কাস্ট করুন একটি বর্ধিত পরিমাণ আপনার পয়েন্টার ফরোয়ার্ড এক্স বাইট এগিয়ে।


4
কেন বিরক্ত হও? এটিকে কেবল সঠিক প্রকারে ফেলে দিন - যা সর্বদা জানা উচিত - এবং যে বৃদ্ধিটি ১ দিয়ে তৈরি করা হয় char, দ্বারা বৃদ্ধি করা xএবং তার পরে নতুন মানটিকে অন্য কোনও ধরণের হিসাবে পুনরায় ব্যাখ্যা করা অর্থহীন এবং অপরিজ্ঞাত আচরণ উভয়ই।
আন্ডারস্কোর_ডে

9
যদি আপনি আপনার সাজান ফাংশনটি লিখছেন, যার মতে এটি man 3 qsortহওয়া উচিত void qsort(void *base, size_t nmemb, size_t size, [snip]), তবে আপনার কাছে "সঠিক ধরণ" জানার কোনও উপায় নেই
এলিসিয়ানোয়

15

সি মান অনুমতি দেয় না অকার্যকর পয়েন্টার এরিথমেটিক। যাইহোক, গনুহ সি আকার বিবেচনা করে অনুমতি দেওয়া হয় অকার্যকর হয় 1

সি 11 স্ট্যান্ডার্ড .26.2.5

অনুচ্ছেদ - 19

এই voidধরণের মানগুলির একটি খালি সেট থাকে; এটি একটি অসম্পূর্ণ বস্তুর প্রকার যা সম্পূর্ণ করা যায় না।

নিম্নলিখিত প্রোগ্রামটি জিসিসি সংকলনে সূক্ষ্মভাবে কাজ করছে।

#include<stdio.h>

int main()
{
    int arr[2] = {1, 2};
    void *ptr = &arr;
    ptr = ptr + sizeof(int);
    printf("%d\n", *(int *)ptr);
    return 0;
}

অন্যান্য সংকলকগুলি একটি ত্রুটি তৈরি করতে পারে।



8

পয়েন্টার গাণিতিক করার আগে আপনাকে এটিকে অন্য ধরণের পয়েন্টারে কাস্ট করতে হবে।


7

অকার্যকর পয়েন্টারগুলি কোনও স্মৃতি অংশকে নির্দেশ করতে পারে। সুতরাং আমরা যখন একটি শূন্য পয়েন্টারে পয়েন্টার গাণিতিক চেষ্টা করি তখন সংকলকটি কত বাইট বৃদ্ধি বা হ্রাস করতে পারে তা জানে না। তাই কোনও পয়েন্টার গাণিতিকের সাথে জড়িত হওয়ার আগে শূন্য পয়েন্টারগুলি অবশ্যই কোনও পরিচিত টাইপের টাইপকাস্ট হতে হবে।

void *p = malloc(sizeof(char)*10);
p++; //compiler does how many where to pint the pointer after this increment operation

char * c = (char *)p;
c++;  // compiler will increment the c by 1, since size of char is 1 byte.

-1

সংকলক টাইপ কাস্ট দ্বারা জানেন। দেওয়া void *x:

  • x+1এতে একটি বাইট যুক্ত হয় x, পয়েন্টার বাইটে যায়x+1
  • (int*)x+1জোড়ে sizeof(int)বাইট, পয়েন্টার বাইট যায়x + sizeof(int)
  • (float*)x+1অ্যাড্রেস sizeof(float)বাইটস, ইত্যাদি

প্রথম আইটেমটি পোর্টেবল নয় এবং সি / সি ++ এর গ্যালাটিওর বিপরীতে রয়েছে, তবুও এটি সি-ভাষা-সঠিক, এর অর্থ এটি বেশিরভাগ সংকলককে সম্ভবত একটি উপযুক্ত পতাকা প্রয়োজনের জন্য সংকলন করবে (যেমন -উপয়েন্টার-এরিথ)


2
Althought the first item is not portable and is against the Galateo of C/C++সত্য। it is nevertheless C-language-correctমিথ্যা। এই দ্বিগুণ! পয়েন্টার গাণিতিকটি void *সিনট্যাক্টিক্যালি অবৈধ, সংকলন করা উচিত নয় এবং যদি তা হয় তবে অপরিবর্তিত আচরণ তৈরি করে। যদি কোনও অসতর্ক প্রোগ্রামার যদি কিছু সতর্কতা অক্ষম করে এটি সংকলন করতে পারে তবে এটি কোনও বাহানা নয়।
আন্ডারস্কোর_ডে

@ আসন্ডার_ডি: আমার মনে হয় কিছু সংকলক এটি একটি এক্সটেনশান হিসাবে এটি ব্যবহার করতে ব্যবহার করত, কারণ এটি পয়েন্টারটিতে unsigned char*একটি sizeofমান যোগ করার চেয়ে কাস্টিংয়ের চেয়ে অনেক বেশি সুবিধাজনক ।
সুপারক্যাট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.