2015-02-17 6 views
8

Например:Передача указателя на локальную переменную: она безопасна?

void func1(){ 
    int i = 123; 
    func2(&i); 
} 
void func2(int *a){ 
    *a = 456; 
} 

Когда func1 вызова func2, указатель на локальную переменную передается func2 - указатель указывает на стек. Это безопасно для правил C?

Спасибо.

+2

Использование указателя на переменную после уничтожения переменной небезопасно. Вы этого не делаете. – immibis

+2

OT: Это должно быть 'void func1 (void)', если для функции не определены аргументы. – alk

+0

Возможный дубликат [Безопасный переход указателя на автоматическую переменную для работы?] (Http://stackoverflow.com/questions/17798785/safe-to-pass-pointer-to-auto-variable-to-function) – ravron

ответ

14

Объем i составляет func1, и он переживает звонок до func2. Так что это совершенно безопасно.

+0

Вы можете увидеть этот вопрос: «http: // stackoverflow. com/questions/34774322/am-i-do-correct-by-through-pointer-to-auto-variable " –

2

Да, безопасно передавать указатель на локальную переменную, но вы не можете вернуть указатель на автоматическую локальную переменную из функции.

+0

Можете ли вы Ответьте на этот вопрос: http://stackoverflow.com/questions/34774322/am-i-doing-correct-by-passing-pointer-to-auto-variable –

1

Да, ваш код в безопасности.

Пока срок жизни объекта не закончен, безопасно передавать локальные переменные, как вы.

1

Это безопасно для правил C?

Что вы делаете, это безопасно, так как локальная переменная по-прежнему действительна и находится в пределах области действия. Доступ к местному варибельному вне его сферы не определен, но это совершенно нормально

1

В вашем случае вы можете безопасно использовать &i до момента, когда время i действительно.

Сейчас, как видим, i имеет всю жизнь до конца func1(). Как, func2() вызывается из func1(), а func1() еще не завершил выполнение, поэтому i по-прежнему действует.

Вот почему, как правило, передавая адрес локальной переменной в другой функции обычно допускается (время жизни переменной не закончена), но, return ИНГ адрес локальной переменной (сразу после return, локальные переменные функция прекратить существовать) не разрешено.

TL; DR: Вы можете смело использовать &i в качестве аргумента func2(), как показано здесь.

+0

* scope * применяется к идентификаторам (а не переменным), и это означает, что этот идентификатор видим, поэтому' i' не имеет значения в 'func2'. Возможно, вы ищете * продолжительность жизни *. –

+0

@MattMcNabb Сэр, теперь я обновил, любезно просмотрел. –

+0

@SouravGhosh Sir Вы можете видеть этот вопрос. «http://stackoverflow.com/questions/34774322/am-i-doing-correct-by-passing-pointer-to-auto-variable» –

3

Как указано в большинстве ответов ранее, совершенно безопасно передавать указатель на func2() в вашем специальном случае.

В реальном мире часть программного обеспечения, однако, я считаю это вредным, поскольку у вас нет контроля над тем, что делает func2() с вашей переменной. func2() может создать псевдоним своего параметра, чтобы использовать его асинхронно в более поздний момент времени. И в это время локальная переменная int i может исчезнуть, когда этот псевдоним будет использоваться позже.

Так что с моей точки зрения передача указателя на локальную (автоматическую) переменную чрезвычайно опасна и ее следует избегать.

Вы можете сделать это, если вы объявляете переменную в func1(), как static int i;

В этом случае обеспечивается, что память i не будут переработаны и перезаписаны. Однако вам потребуется настроить блокировку Mutex для управления доступом к этой памяти в параллельной среде.

Чтобы проиллюстрировать эту проблему, вот какой-то код, который я только что споткнулся вчера во время тестирования программного обеспечения у моего клиента. И да, он выходит из строя ...

void func1() 
{ 
    // Data structure for NVMemory calls 
    valueObj_t NVMemObj; 

    // a data buffer for eeprom write 
    UINT8 DataBuff[25]; 
    // [..] 
    /* Assign the data pointer to NV Memory object */ 
    NVMemObj.record = &DataBuff[0]; 
    // [..] 
    // Write parameter to EEPROM. 
    (void)SetObject_ASync(para1, para2, para3, &NVMemObj); 
    return; 
} 

void SetObject_ASync(para1, para2, para3, valueObj_t *MemoryRef) 
{ 
    //[..] 
    ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr = MemoryRef->record; 
    //[..] 
    return; 
} 

В этом случае, данные в DataBuff давно нет, когда указатель в ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr используется для хранения данных в EEPROM.

Чтобы исправить этот код, по крайней мере необходимо объявить static UINT8 DataBuff[25]; Кроме того, считается, что также объявлено static valueObj_t NVMemObj, поскольку мы не знаем, что вызываемая функция выполняет с этим указателем.

Выражаясь кратко: TL; DR

Несмотря на то, что это законно в языке Си, я считаю это вредным передавать указатели на автоматические переменные в вызове функции. Вы никогда не знаете (и часто не хотите знать), что именно вызываемая функция выполняет с переданными значениями. Когда вызываемая функция устанавливает псевдоним, вы получаете большие неприятности.

Только мои 2 цента.

+3

«func2() может создать псевдоним своего параметра, чтобы использовать его асинхронно на более поздний момент времени ». Тем не менее, то же самое можно сказать и о malloced памяти, которую вы передаете в функцию ... он может создать псевдоним для него, который он пытается получить после того, как вызывающий пользователь освободит память. Дело здесь не в том, что вызывающий абонент делает что-то неправильно, но вызываемая функция * сохраняет ссылки (где? В глобальном?) На собственные аргументы, что она повторно использует в * более поздних вызовах *. Также считайте, что это более безопасная отправная точка, поскольку их не нужно освобождать. TLDR; автоматические переменные = хорошие. Функции, содержащие указатели на их аргументы = плохо. – aaa90210

Смежные вопросы