সিএমকে ফাংশন বনাম ম্যাক্রো


90

সিএমকে 2.8.12 এর সরকারী দস্তাবেজ সম্পর্কে বলা হয়েছেmacro

এটি আহ্বান করা হলে, ম্যাক্রোতে রেকর্ডকৃত কমান্ডগুলি প্রথমে আর্গুমেন্টগুলি পাস করার সাথে ফর্মাল প্যারামিটারগুলি ($ g arg1}) প্রতিস্থাপন করে এবং তারপরে সাধারণ কমান্ড হিসাবে আহ্বান করা হয়।

এবং সম্বন্ধে function

এটি যখন আহ্বান করা হয়, ফাংশনে রেকর্ডকৃত কমান্ডগুলি প্রথমে আর্গুমেন্টগুলি পাস করার সাথে ফর্মাল প্যারামিটারগুলি ($ g arg1}) প্রতিস্থাপন করে এবং তারপরে সাধারণ কমান্ড হিসাবে আহ্বান করা হয়।

স্পষ্টতই, দুটি উক্তি প্রায় একই তবে আমাকে বিভ্রান্ত করছে। ঠিক কখন ম্যাক্রোর মতো কোনও ফাংশন কল করার সময় প্যারামিটারগুলি প্রতিস্থাপন করে?


8
সেখানে অন্তত একটি অন্যান্য গুরুত্বপূর্ণ, যদিও মোটামুটি সুস্পষ্ট মধ্যে পার্থক্য functionএবং macroএর শব্দার্থবিদ্যা: return()যখন একটি ব্যবহৃত: macro, আপনি ম্যাক্রো থেকে কিন্তু কলিং ফাংশন থেকে ফিরে করা হবে না।
জোচিম ডব্লিউ

4
আরেকটি গুরুত্বপূর্ণ দ্রষ্টব্য, ম্যাক্রোর দ্বি-দ্বারগুলিতে দ্বি-পাস সম্প্রসারণের মঞ্চ থাকে যখন কোনও ক্রিয়াকলাপ কেবল একটিই থাকে। এই ম্যাক্রো এবং ফাংশন তৈরি করার চেষ্টা করুন এবং ${ARGV}ভিতরে থেকে মুদ্রণ করুন : macro(my_macro), function(my_func)। আর তাদের ব্যবহার করুন: set(a 123), my_macro("\\\${a}\\\\;\\\;;"), my_func(\${a}\\;\;;)। আপনি ডবল পালাবার আছে সব পাবেন $, \ , ;সঠিকভাবে সমগ্র স্ট্রিং নেস্টেড কমান্ড অপরিবর্তিত পাস। এটি আসল cmake 3.14+
অ্যান্ড্রি

উত্তর:


95

আমি নীচে একটি নমুনা কোড লিখেছি:

set(var "ABC")

macro(Moo arg)
  message("arg = ${arg}")
  set(arg "abc")
  message("# After change the value of arg.")
  message("arg = ${arg}")
endmacro()
message("=== Call macro ===")
Moo(${var})

function(Foo arg)
  message("arg = ${arg}")
  set(arg "abc")
  message("# After change the value of arg.")
  message("arg = ${arg}")
endfunction()
message("=== Call function ===")
Foo(${var})

এবং আউটপুটটি হ'ল:

=== Call macro ===
arg = ABC
# After change the value of arg.
arg = ABC
=== Call function ===
arg = ABC
# After change the value of arg.
arg = abc

সুতরাং মনে argহয় varকল করার সময় এর মূল্য নির্ধারিত হয় Fooএবং কল ${arg}করার ${var}সময় কেবল স্ট্রিং প্রতিস্থাপন করা হয় Moo

তাই আমি মনে করি দুই কোট সর্বোপরি, খুব সহজ এক বিভ্রান্ত করতে যদিও অফিসিয়াল নথি বলেন যে :

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


আমি তা ভুলে গেছি, তবে আমার মনে হয় এটি হতে পারে।
ইয়ানতাও জে

4
@ রবার্ট আপনার নিজের প্রশ্নের উত্তর অবিলম্বে সহায়তা কেন্দ্র হিসাবে অনুমোদিত হয়েছে (বিশেষত যদি এটি অন্যের কাছে সাধারণ আগ্রহের একটি ভাল, নকল নয়)) এটি এসওকে আরও ভাল জ্ঞানের ভিত্তিতে পরিণত করতে সহায়তা করা। আপনি কি সেই সহায়তা কেন্দ্রের বিষয়ে লিঙ্কযুক্ত ব্লগ পোস্টটি পড়েছেন? stackoverflow.blog/2011/07/01/…
এমিল কর্মিয়ার

4
@ আরবার্ট আমি এসইওর প্রতিষ্ঠাতা নিজেই এই অনুশীলন সম্পর্কে কী ভাবছেন তা রিলে করছি। ওকে সাথে নিয়ে যাও। ;-)
এমিল কর্মিয়ার

4
এর সাথে এরকম উদাহরণ চালানো cmake --trace-expandআলোকিত
মারক এইচ

4
প্রতিটি কলের পরে নিম্নলিখিত কমান্ডটি যুক্ত করে বিবেচনা করুন: message("# arg in main scope = '${arg}'")ম্যাক্রোর আগে ফাংশনটি কল করা।
মার্চ

34

অন্য কথায়, ফাংশনটি নতুন ভেরিয়েবল স্কোপটি পুশ করে এবং পপ করে (ভেরিয়েবলগুলি কেবলমাত্র ফাংশনে উপস্থিত এবং পরিবর্তিত হয়), ম্যাক্রো থাকে না। তবে আপনি কমান্ডের PARENT_SCOPEপ্যারামিটার দিয়ে ফাংশন ডিফল্ট আচরণকে ওভাররাইড করতে পারেন set


8

আপনার উদ্ধৃত করা কমক ডকুমেন্টেশন এতটাই বিভ্রান্তিকর যে এটি মূলত ভুল। এটি এর মতো স্পষ্ট / স্থির করা উচিত:

  • ম্যাক্রো: যখন এটি আহ্বান করা হয়, ম্যাক্রোতে রেকর্ডকৃত কমান্ডগুলি প্রথমে প্রথমে আর্গুমেন্টগুলি দিয়ে formal {arg1}) আনুষ্ঠানিক পরামিতি ($ g arg1}) প্রতিস্থাপন করে চালানোর আগে সমস্তগুলি সংশোধন করা হয়।

cmake --trace-expand ঠিক কী ঘটে তা দেখায়।

Cmake 3.13.3 ডক এই ক্ষেত্রে 2.8.12 এর সাথে তুলনা করে পরিবর্তিত হয়নি।


3

ম্যাক্রো সম্প্রসারণ, Yantao জাই উত্তর সত্যিই আমার চোখ খোলে!

আমি নীচে টিউটোরিয়ালটি কিছু কংক্রিট উদাহরণ সহ দেখতে পেয়েছি যা ভেরিয়েবল স্কোপ ধারণাটি বুঝতে সহায়তা করে।

15 মিনিটের মধ্যে শিখুন সিএমকে থেকে উদ্ধৃত :

সিএমকেতে, আপনি কোনও ক্রিয়া সংজ্ঞায়িত করতে একজোড়া function/ endfunctionকমান্ড ব্যবহার করতে পারেন । এখানে এমন একটি যা তার যুক্তির সংখ্যার মানকে দ্বিগুণ করে, তারপরে ফলাফলটি মুদ্রণ করে:

function(doubleIt VALUE)
    math(EXPR RESULT "${VALUE} * 2")
    message("${RESULT}")
endfunction()

doubleIt("4")                           # Prints: 8

ফাংশনগুলি তাদের নিজস্ব স্কোপে চলে। কোনও ফাংশনে সংজ্ঞায়িত কোন ভেরিয়েবল কলারের সুযোগকে দূষিত করে না। যদি আপনি কোনও মান ফিরিয়ে দিতে চান তবে আপনি কোনও ভেরিয়েবলের নামটি আপনার ফাংশনে প্রেরণ করতে পারেন, তারপরে setবিশেষ যুক্তি দিয়ে কমান্ডটি কল করুন PARENT_SCOPE:

function(doubleIt VARNAME VALUE)
    math(EXPR RESULT "${VALUE} * 2")
    set(${VARNAME} "${RESULT}" PARENT_SCOPE)    # Set the named variable in caller's scope
endfunction()

doubleIt(RESULT "4")                    # Tell the function to set the variable named RESULT
message("${RESULT}")                    # Prints: 8

একইভাবে, একজোড়া macro/ endmacroকমান্ড ম্যাক্রো সংজ্ঞা দেয়। ফাংশনগুলির বিপরীতে, ম্যাক্রোগুলি তাদের কলারের মতো একই স্কোপে চলে। সুতরাং, ম্যাক্রোর অভ্যন্তরে সংজ্ঞায়িত সমস্ত ভেরিয়েবলগুলি কলারের স্কোপে সেট করা থাকে। আমরা নিম্নলিখিত ফাংশন প্রতিস্থাপন করতে পারেন:

macro(doubleIt VARNAME VALUE)
    math(EXPR ${VARNAME} "${VALUE} * 2")        # Set the named variable in caller's scope
endmacro()

doubleIt(RESULT "4")                    # Tell the macro to set the variable named RESULT
message("${RESULT}")                    # Prints: 8

উভয় ফাংশন এবং ম্যাক্রোগুলি একটি স্বেচ্ছাসেবী যুক্তি স্বীকার করে। নামহীন আর্গুমেন্টগুলি একটি বিশেষ ভেরিয়েবলের মাধ্যমে তালিকা হিসাবে ফাংশনটির কাছে প্রকাশিত হয় ARGN

এখানে একটি ফাংশন যা এটি প্রাপ্ত প্রতিটি আর্গুমেন্টকে দ্বিগুণ করে প্রতিটি পৃথক লাইনে মুদ্রণ করে:

function(doubleEach)
    foreach(ARG ${ARGN})                # Iterate over each argument
        math(EXPR N "${ARG} * 2")       # Double ARG's numeric value; store result in N
        message("${N}")                 # Print N
    endforeach()
endfunction()

doubleEach(5 6 7 8)                     # Prints 10, 12, 14, 16 on separate lines

3

মধ্যে আরেকটি উল্লেখযোগ্য পার্থক্য function()এবং macro()এর আচরণ return()

প্রত্যাবর্তনের ()) এর ক্যামেক ডকুমেন্টেশন থেকে :

মনে রাখবেন যে কোনও ম্যাক্রো, কোনও ফাংশন থেকে ভিন্ন, স্থানে প্রসারিত এবং তাই রিটার্নটি হ্যান্ডেল করতে পারে না।

সুতরাং এটি স্থানে প্রসারিত হওয়ার কারণে এটি macro()কলার থেকে ফিরে আসে। একটি ফাংশনে থাকাকালীন এটিটি প্রস্থান করেfunction()

উদাহরণ:

macro(my_macro)
    return()
endmacro()

function(my_function)
    return()
endfunction()

my_function()
message(hello) # is printed
my_macro()
message(hi) # is not printed

0

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

আরও বিশদের জন্য: https://levelup.gitconnected.com/cmake-variable-scope-f062833581b7


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

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