[英]Using function parameter as variable
在函數內部重新分配函數參數是不好的做法還是好的做法,或者是不確定的行為?
讓我用一個例子來說明我要做什么:
void
gkUpdateTransforms(GkNode *node /* other params */) {
GkNode *nodei;
if (!(nodei = node->chld))
return;
do {
/* do job */
nodei = nodei->next;
} while (nodei);
}
選擇:
void
gkUpdateTransforms2(GkNode *node /* other params */) {
/* node parameter is only used here to get chld, not anywhere else */
if (!(node = node->chld))
return;
do {
/* do job */
node = node->next;
} while (node);
}
我檢查了程序集的輸出,看起來好像一樣,我們不需要在第二個中聲明一個變量。 您可能會問,如果更改了參數類型,但是對於第一個參數,相同的條件將是相同的,因為它也需要更新。
編輯:參數是按值傳遞,我的意圖不是編輯指針本身
EDIT2:遞歸函數呢? 如果gkUpdateTransforms2是遞歸的,會發生什么? 我很困惑,因為函數會自行調用,但我認為在每次調用中,參數都會不同
我不知道您為什么認為這將是未定義的行為-事實並非如此。 通常,這只是編碼風格的問題,沒有明顯的對與錯。
通常,優良作法是將參數視為不可變對象 。 保留功能的原始輸入副本是很有用的。 因此,最好使用局部變量,該局部變量只是參數的副本。 如您所見,這絲毫不影響性能-編譯器將優化代碼。
但是,如果您也寫入參數,則沒什么大不了的。 這也是常見的做法。 稱其為不良做法將非常令人討厭。
如果不應該修改某些函數式編碼樣式,則所有函數參數都將變為const
,但我個人認為這只是混淆,這會使代碼更難閱讀。 在您的情況下,這種學究式樣式將為void gkUpdateTransforms(GkNode*const node)
。 不要與const正確性相混淆,const正確性是一件普遍的事情,而不僅僅是樣式問題。
但是,您的代碼中確實存在某些絕對不正確的做法,那就是在條件內部進行賦值。 盡可能避免這種情況,這很危險,並使代碼更難閱讀。 大多數情況下沒有好處。
在C的歷史早期就注意到混合=
和==
的危險。為了解決這一問題,在1980年代,人們想到了諸如“尤達條件”之類的對大腦造成傷害的事物。 然后在1989年左右出現了Borland Turbo C,它具有精美的警告功能“可能錯誤分配”。 那是Yoda條件的死亡,從那時起,編譯器就警告不要指定條件。
確保當前的編譯器對此發出警告。 也就是說,請確保不要使用比1989年的Borland Turbo更差的編譯器。是的,市場上有較差的編譯器。
(gcc給出了“警告:建議將用作真值的賦值括號括起來”)
我將代碼寫為
void gkUpdateTransforms(GkNode* node /* other params */)
{
if(node == NULL)
{
return ;
}
for(GkNode* i=node->chld; i!=NULL; i=i->next;)
{
/* do job */
}
}
這主要是風格上的更改,以使代碼更具可讀性。 它不會大大提高性能。
恕我直言,這不是完全“壞”的做法,但是值得懷疑的是,沒有更好的方法。 關於分析匯編程序輸出:它可能是有趣而有教育意義的外觀,但是不建議您使用它作為優化或更糟的源代碼懶惰的理由。 下一個編譯器或下一個體系結構可能只會使您的想法完全無效-我的建議是在這里與Knuth保持聯系: “與其想象我們的主要任務是指導計算機做什么,不如讓我們專注於向人類解釋我們想讓計算機做什么。” 。
在您的代碼中,我認為決定是50:50,沒有明確的獲勝者。 我認為節點迭代器有一個自己的概念,可以證明一個單獨的編程結構(在我們的例子中只是一個變量)是合理的,但是函數又是如此的簡單,以至於在下一個方面,我們並沒有贏得太多程序員查看您的代碼,因此我們可以很好地使用第二個版本。 如果您的功能開始隨着時間的推移而變異和增長,則此前提可能會失效,我們最好選擇第一個版本。 也就是說,我會像這樣編寫第一個版本:
void
gkUpdateTransforms(GkNode *node /* other params */) {
for (GkNode *nodei = node->chld; nodei != NULL; nodei = nodei->next) {
/* do job */
}
}
這是定義明確的,也是實現此行為的完美方法。
您可能將其視為問題的原因是執行以下操作的常見錯誤:
int func(object a) {
modify a // only modifying copy, but user expects a to be modified
但是對於您的情況,您希望復制該指針。
只要按值傳遞它,就可以將其安全地視為任何其他局部變量。 在這種情況下,這不是一個壞習慣,也不是未定義的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.