C99 'সীমাবদ্ধ' কীওয়ার্ডটির বাস্তবিক ব্যবহার?


182

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

যে কেউ বাস্তবে এটি ব্যবহার করে এমন কিছু বাস্তবের প্রস্তাব দিতে পারে?


4
memcpyবনাম memmoveএকটি প্রথাগত উদাহরণ।
আলেকজান্দ্রি সি

@ অ্যালেক্সানড্রেসি: আমি মনে করি না যে এটি একটি বিশেষভাবে প্রযোজ্য, কারণ "সীমাবদ্ধ" কোয়ালিফায়ারের অভাবে প্রোগ্রামের যুক্তি ওভারলোডিং উত্স এবং গন্তব্য নিয়ে কাজ করবে না বা এ জাতীয় যোগ্যতার উপস্থিতি কোনও তথাকথিত পদ্ধতি থেকে বাধা দেবে না nor উত্স এবং গন্তব্য ওভারল্যাপ হয়েছে কিনা তা নির্ধারণ করে এবং যদি তাই হয় তবে src + (ডেসট-সিআরসি) দিয়ে গন্তব্য প্রতিস্থাপন করা হবে, যেহেতু এটি এসসিআর থেকে প্রাপ্ত তাই এটির উপকরণের অনুমতি দেওয়া হবে।
সুপারক্যাট

@ সুপের্যাট: এজন্য আমি এটিকে একটি মন্তব্য হিসাবে রেখেছি। যাইহোক, 1) restrictযোগ্যতামূলক যুক্তি memcpyনীতিগতভাবে একটি নিষ্প্রভ বাস্তবায়নকে আক্রমণাত্মকভাবে অনুকূল করা যায় এবং 2) কেবল কলিং সংকলককে memcpyএটি ধরে নিতে সক্ষম করে যে এটি প্রদত্ত যুক্তিগুলি উপাধি দেয় না, যা memcpyকলটির আশেপাশে কিছু অপ্টিমাইজেশনের অনুমতি দিতে পারে ।
আলেকজান্দ্রি সি

@ আলেকজান্দ্রিক .: বেশিরভাগ প্ল্যাটফর্মের সংকলকটির পক্ষে নির্দোষ ম্যাকপি - এমনকি "সীমাবদ্ধ" - দিয়ে লক্ষ্য অনুসারে সংস্করণ হিসাবে যতটা দক্ষতার কাছাকাছি থাকতে পারে তার অনুকূলকরণ করা খুব কঠিন। কল-সাইড অপ্টিমাইজেশানগুলির জন্য "সীমাবদ্ধ" কীওয়ার্ডের প্রয়োজন হবে না এবং কিছু ক্ষেত্রে সেগুলি সহজ করার প্রচেষ্টা প্রচুর পরিমাণে উত্পাদনশীল হতে পারে। উদাহরণস্বরূপ, মেমকপির অনেকগুলি বাস্তবায়ন শূন্যের অতিরিক্ত ব্যয়কে memcpy(anything, anything, 0);নো-অফ হিসাবে বিবেচনা করতে পারে এবং নিশ্চিত করতে পারে যে যদি pকমপক্ষে nলিখনযোগ্য বাইটের পয়েন্টার হয় memcpy(p,p,n); কোন প্রতিকূল পার্শ্ব প্রতিক্রিয়া আছে। এই জাতীয় কেসগুলি দেখা দিতে পারে ...
সুপারক্যাট

... প্রাকৃতিকভাবে কিছু নির্দিষ্ট অ্যাপ্লিকেশন কোডে (যেমন একটি আইটেমটি নিজের সাথে সরিয়ে দেওয়ার নিয়মিত রুটিন), এবং বাস্তবায়নের ক্ষেত্রে যেখানে তাদের কোনও বিরূপ পার্শ্ব প্রতিক্রিয়া নেই, জেনারেল-কেস কোড দ্বারা এই কেসগুলি পরিচালনা করা কার্যকর হওয়ার চেয়ে আরও কার্যকর হতে পারে বিশেষ ক্ষেত্রে পরীক্ষা যোগ করতে। দুর্ভাগ্যক্রমে, কিছু সংকলক লেখক মনে করেন যে প্রোগ্রামাররা কোড সংযোজনকারী সংযোজনকারী সংযোজন করতে পারে না তার চেয়ে আরও ভাল হবে, যাতে "অপটিমাইজেশন সুযোগগুলি" সহজলভ্য করতে পারে যা সংকলকরা খুব কমই অন্যায়ভাবে কাজে লাগাতে পারে।
ক্যাট

উত্তর:


180

restrictবলে যে পয়েন্টার হ'ল একমাত্র জিনিস যা অন্তর্নিহিত বস্তুকে অ্যাক্সেস করে। এটি পয়েন্টার আলিয়াসিংয়ের সম্ভাবনাগুলি সরিয়ে দেয় এবং সংকলক দ্বারা আরও ভাল অপ্টিমাইজেশন সক্ষম করে।

উদাহরণস্বরূপ, ধরুন আমার কাছে এমন একটি মেশিন রয়েছে যাতে বিশেষ নির্দেশাবলী রয়েছে যা মেমরিতে সংখ্যার ভেক্টরকে গুণ করতে পারে এবং আমার কাছে নিম্নলিখিত কোডটি রয়েছে:

void MultiplyArrays(int* dest, int* src1, int* src2, int n)
{
    for(int i = 0; i < n; i++)
    {
        dest[i] = src1[i]*src2[i];
    }
}

সংকলকটির সঠিকভাবে পরিচালনা করা দরকার যদি dest, src1এবং src2ওভারল্যাপ হয়, এর অর্থ এটি শুরু থেকে শেষ পর্যন্ত একবারে একটি গুণ করতে হবে। থাকার দ্বারা restrict, সংকলক ভেক্টর নির্দেশাবলী ব্যবহার করে এই কোডটি অনুকূল করতে মুক্ত।

উইকিপিডিয়ায় একটি এন্ট্রি রয়েছে restrict, এখানে আরও একটি উদাহরণ রয়েছে


3
@ মিশেল - যদি আমি ভুল না করে থাকি তবে সমস্যাটি তখনই হবে যখন destউত্স ভেক্টরগুলির মধ্যে কোনওটি ওভারল্যাপিং করা হবে। কেন একটি সমস্যা যদি হবে src1এবং src2ওভারল্যাপ?
ysap

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

লুপ ভেরিয়েবলের জন্য রেজিস্টার কীওয়ার্ড যুক্ত করা সীমাবদ্ধ করার পাশাপাশি এটি আরও দ্রুত করে তোলে।

2
আসলে, রেজিস্টার কীওয়ার্ডটি কেবলমাত্র পরামর্শমূলক। এবং প্রায় 2000 সাল থেকে সংকলকগুলিতে, উদাহরণস্বরূপ i (এবং তুলনা করার জন্য এন) আপনি নিবন্ধক কীওয়ার্ডটি ব্যবহার করেন বা না করেন তা একটি নিবন্ধে অনুকূলিত হবে।
মার্ক ফিশলার

152

উইকিপিডিয়া উদাহরণ হয় খুব আলোকজ্জ্বল।

এটি স্পষ্টভাবে দেখায় যে এটি কীভাবে একটি সমাবেশ নির্দেশকে সংরক্ষণ করতে দেয়

সীমাবদ্ধ ছাড়াই:

void f(int *a, int *b, int *x) {
  *a += *x;
  *b += *x;
}

সিউডো সমাবেশ:

load R1  *x    ; Load the value of x pointer
load R2  *a    ; Load the value of a pointer
add R2 += R1    ; Perform Addition
set R2  *a     ; Update the value of a pointer
; Similarly for b, note that x is loaded twice,
; because a may be equal to x.
load R1  *x
load R2  *b
add R2 += R1
set R2  *b

সীমাবদ্ধ সহ:

void fr(int *restrict a, int *restrict b, int *restrict x);

সিউডো সমাবেশ:

load R1  *x
load R2  *a
add R2 += R1
set R2  *a
; Note that x is not reloaded,
; because the compiler knows it is unchanged
; load R1  *x
load R2  *b
add R2 += R1
set R2  *b

জিসিসি কি আসলেই তা করে?

জিসিসি 4.8 লিনাক্স x86-64:

gcc -g -std=c99 -O0 -c main.c
objdump -S main.o

সাথে -O0, তারা একই।

সহ -O3:

void f(int *a, int *b, int *x) {
    *a += *x;
   0:   8b 02                   mov    (%rdx),%eax
   2:   01 07                   add    %eax,(%rdi)
    *b += *x;
   4:   8b 02                   mov    (%rdx),%eax
   6:   01 06                   add    %eax,(%rsi)  

void fr(int *restrict a, int *restrict b, int *restrict x) {
    *a += *x;
  10:   8b 02                   mov    (%rdx),%eax
  12:   01 07                   add    %eax,(%rdi)
    *b += *x;
  14:   01 06                   add    %eax,(%rsi) 

নিরবচ্ছিন্নদের জন্য, কলিং কনভেনশনটি হ'ল:

  • rdi = প্রথম প্যারামিটার
  • rsi = দ্বিতীয় প্যারামিটার
  • rdx = তৃতীয় পরামিতি

জিসিসি আউটপুটটি উইকির নিবন্ধের চেয়ে আরও পরিষ্কার ছিল: 4 টি নির্দেশাবলী বনাম 3 নির্দেশাবলী।

অ্যারেগুলির

এখনও অবধি আমাদের একক নির্দেশনা সঞ্চয় রয়েছে, তবে যদি পয়েন্টারটি সাধারণ ব্যবহারের ক্ষেত্রে লুপ করা হবে এমন অ্যারেগুলি উপস্থাপন করে, তবে সুপারক্যাট দ্বারা উল্লিখিত নির্দেশাবলীর একগুচ্ছ সংরক্ষণ করা যেতে পারে ।

উদাহরণস্বরূপ বিবেচনা করুন:

void f(char *restrict p1, char *restrict p2) {
    for (int i = 0; i < 50; i++) {
        p1[i] = 4;
        p2[i] = 9;
    }
}

কারণ restrict, একটি স্মার্ট কম্পাইলার (অথবা মানব), যে নিখুত পারে:

memset(p1, 4, 50);
memset(p2, 9, 50);

যেটি সম্ভাব্যভাবে অনেক বেশি কার্যকর কারণ এটি একটি শালীন libc বাস্তবায়নের (যেমন গ্লিবসি) অ্যাসেম্বলিটি অনুকূল হতে পারে: পারফরম্যান্সের ক্ষেত্রে স্ট্যান্ড :: মেমকি () বা স্টাডি :: কপি () ব্যবহার করা কি আরও ভাল?

জিসিসি কি আসলেই তা করে?

জিসিসি 5.2.1. লিনাক্স x86-64 উবুন্টু 15.10:

gcc -g -std=c99 -O0 -c main.c
objdump -dr main.o

সঙ্গে -O0 , উভয় একই।

সহ -O3:

  • সীমাবদ্ধ সহ:

    3f0:   48 85 d2                test   %rdx,%rdx
    3f3:   74 33                   je     428 <fr+0x38>
    3f5:   55                      push   %rbp
    3f6:   53                      push   %rbx
    3f7:   48 89 f5                mov    %rsi,%rbp
    3fa:   be 04 00 00 00          mov    $0x4,%esi
    3ff:   48 89 d3                mov    %rdx,%rbx
    402:   48 83 ec 08             sub    $0x8,%rsp
    406:   e8 00 00 00 00          callq  40b <fr+0x1b>
                            407: R_X86_64_PC32      memset-0x4
    40b:   48 83 c4 08             add    $0x8,%rsp
    40f:   48 89 da                mov    %rbx,%rdx
    412:   48 89 ef                mov    %rbp,%rdi
    415:   5b                      pop    %rbx
    416:   5d                      pop    %rbp
    417:   be 09 00 00 00          mov    $0x9,%esi
    41c:   e9 00 00 00 00          jmpq   421 <fr+0x31>
                            41d: R_X86_64_PC32      memset-0x4
    421:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    428:   f3 c3                   repz retq

    memsetপ্রত্যাশা অনুযায়ী দুটি কল।

  • কোনও সীমাবদ্ধ ছাড়াই: কোনও স্টিডলিব কল নেই, কেবলমাত্র 16 টি পুনরাবৃত্তির প্রশস্ত লুপটি আন্রোলিং করছে যা আমি এখানে পুনরুত্পাদন করার উদ্দেশ্যে চাই না :-)

আমি তাদের মানদণ্ডে ধৈর্য ধরিনি, তবে আমি বিশ্বাস করি যে সীমাবদ্ধ সংস্করণটি আরও দ্রুত হবে।

C99

সম্পূর্ণতার জন্য স্ট্যান্ডার্ডটি দেখুন।

restrictবলেছেন যে দুটি পয়েন্টার ওভারল্যাপিং মেমরি অঞ্চলে নির্দেশ করতে পারে না। সর্বাধিক সাধারণ ব্যবহার হ'ল ফাংশন আর্গুমেন্টের জন্য।

এটি কীভাবে ফাংশনটি বলা যেতে পারে তা সীমাবদ্ধ করে তবে আরও সংকলন-সময় অপ্টিমাইজেশনের অনুমতি দেয়।

যদি কলার restrictচুক্তিটি অনুসরণ না করে তবে অপরিবর্তিত আচরণ।

C99 N1256 খসড়া 6.7.3 / 7 "প্রকার কোয়ালিফায়ার" বলেছেন:

সীমাবদ্ধ কোয়ালিফায়ার (যেমন রেজিস্টার স্টোরেজ ক্লাসের) এর উদ্দেশ্যযুক্ত ব্যবহারটি অপ্টিমাইজেশান প্রচার করা, এবং একটি মানানসই প্রোগ্রাম রচনা করে সমস্ত প্রিপ্রোসেসিং অনুবাদ ইউনিট থেকে বাছাইপর্বের সমস্ত উদাহরণ মুছে ফেলার অর্থ এর অর্থ পরিবর্তন হয় না (অর্থাত্ পর্যবেক্ষণযোগ্য আচরণ)।

এবং 7.7.৩.১ "সীমাবদ্ধতার আনুষ্ঠানিক সংজ্ঞা" গুরুর বিবরণ দেয়।

কঠোর আলিয়াজিংয়ের নিয়ম

restrictমূলশব্দটি কেবল সামঞ্জস্যপূর্ণ ধরণের পয়েন্টারগুলিকেই প্রভাবিত করে (উদাহরণস্বরূপ দুটি int*) কারণ কঠোর আলিয়াজিং বিধিগুলি বলে যে অসামঞ্জস্যিত প্রকারের aliasing ডিফল্টরূপে সংজ্ঞায়িত আচরণ, এবং তাই সংযোজকরা ধরে নিতে পারে এটি ঘটে না এবং অপ্টিমাইজ করা যায় না।

দেখুন: আলিয়াসের কঠোর নিয়ম কী?

আরো দেখুন


9
"সীমাবদ্ধ" কোয়ালিফায়ার আসলে অনেক বড় সঞ্চয়কে মঞ্জুরি দিতে পারে। উদাহরণস্বরূপ, প্রদত্ত void zap(char *restrict p1, char *restrict p2) { for (int i=0; i<50; i++) { p1[i] = 4; p2[i] = 9; } }, সীমাবদ্ধ কোয়ালিফায়ার সংকলক কোডটিকে "মেমসেট (পি 1,4,50); মেমসেট (পি 2,9,50);" হিসাবে আবার লিখতে দেয়। টাইপ-বেসড এলিয়াসিংয়ের চেয়ে সীমাবদ্ধতা অনেক বেশি উচ্চতর; এটি লজ্জার সংকলকগণ পরবর্তীকালে আরও বেশি ফোকাস করে।
সুপারক্যাট

@ সুপের্যাট দুর্দান্ত উদাহরণ, উত্তরে যুক্ত হয়েছে।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

2
@ টিম 18: "সীমাবদ্ধ" কীওয়ার্ডটি অনেকগুলি অপ্টিমাইজেশন সক্ষম করতে পারে যা আক্রমণাত্মক টাইপ-ভিত্তিক অপ্টিমাইজেশনও পারে না। তদুপরি, ভাষায় "সীমাবদ্ধ" অস্তিত্ব - আক্রমণাত্মক টাইপ-ভিত্তিক এলিয়াসিংয়ের বিপরীতে - তাদের অনুপস্থিতিতে যতটা সম্ভব দক্ষতার সাথে কাজ সম্পাদন করা কখনই অসম্ভব করে না (যেহেতু "সীমাবদ্ধ" দ্বারা ভেঙে দেওয়া কোডটি কেবল সহজেই পারে) এটি ব্যবহার করবেন না, যখন আক্রমণাত্মক টিবিএএ দ্বারা বিভক্ত কোডটি প্রায়শই কম দক্ষ ফ্যাশনে আবার লিখতে হবে)।
সুপারক্যাট

2
@ টিম 18: চারপাশের জিনিসগুলি যেমন ব্যাকটিক্সগুলিতে ডাবল-আন্ডারলাইন ধারণ করে __restrict। অন্যথায় ডাবল-আন্ডারলাইনগুলি আপনি চিৎকার করছেন এমন ইঙ্গিত হিসাবে ভুল ব্যাখ্যা করা যেতে পারে।
সুপারক্যাট

1
চেঁচামেচি না করার চেয়ে আরও গুরুত্বপূর্ণ এটি হ'ল আন্ডারস্কোরগুলির অর্থ আপনি যে পয়েন্টটি করতে চেষ্টা করছেন তার সাথে সরাসরি প্রাসঙ্গিক।
পুনরুদ্ধারগুলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.