2015-01-30 3 views
7

Если функция объявлена ​​какC: как объявить статическую функцию, которая возвращает нестатистическую строку?

static char *function(...) { ... } 

Означает ли это, что это нестатическая функция, которая возвращает static char * или статическую функцию, которая возвращает нестатический char *?

Сравните следующие две функции. Какой из них правильный?

static char *fn1(void) 
{ 
    static char s[] = "hello"; 
    return s; 
} 


static char *fn2(void) 
{ 
    char *s = malloc(6); 
    strcpy(s, "world"); 
    return s; 
} 
+0

'статический символ *' не тип –

+0

На самом деле, 'void' является излишним и делает некоторые компиляторы сломаться. –

+0

@ Prof.Falken, я думаю, что 'fn1 (void)', в C89, по крайней мере, означает, что я объявляю функцию, которая не принимает параметр, в то время как 'fn1()' означает, что параметры неуточнены (то есть в старых когда идея прототипа не была изобретена). Я ошибаюсь? – hbp

ответ

8

static относится к функции, а не к ее типу возврата. Обе эти функции правильны - разница в том, что s будет инициализирован один раз при первом вызове fn1, и все вызовы fn1 делят s; тогда как в fn2, новый s будет выделен для каждого вызова. И так как оба fn1 и fn2 имеют связь static, они будут закрыты для единицы перевода (исходный файл, приблизительно), где они определены.

+0

Благодарим вас за четкое объяснение. – hbp

3

Оба определения вашей функции верны.

Точка для заметок, static здесь используется для ограничения функции в области видимости файла, а не для указания типа возврата, то есть эта функция может использоваться [называемой] другими функциями, находящимися в том же файле, но не функции, которые присутствуют в некоторых других файлах, хотя они, возможно, были скомпилированы и связаны вместе, чтобы сформировать двоичный файл.

+0

Благодарим вас за объяснение. – hbp

3

static прежде чем функция относится к функции, а не его тип (или даже часть его, как и возвратного типа):
Это означает, что функция имеет статическую связь, ака перевод-блок/локальный файл (и таким образом, очень вероятно, что они будут включены).

Обе функции являются правильными, хотя они имеют различную семантику:

  • Первый возвращает указатель на статический массив, содержимое которого может быть изменен. Остерегайтесь проблем параллелизма и повторного входа, если вы это сделаете.
  • Второй выделяет некоторую кучную память, инициализирует ее строкой и возвращает это. Помните, free это.
+0

Благодарим вас за ответ! – hbp

1

Ключевое слово static при использовании с определением функции говорит о том, что функция имеет область уровня файла. Это означает, что имя функции отображается только внутри самого файла. Ключевое слово static, используемое в определении функции, изменяет видимость имени функции и не изменяет тип возвращаемой функции.

Таким образом, функция, объявленная static, может возвращать любой тип.

Использование static для переменной, определенной в теле функции, используется для указания того, что переменная должна быть создана в момент загрузки и запуска приложения. Поэтому, если вы используете модификатор static для переменной внутри функции, эта переменная не создается в стеке при вызове функции. Он существует независимо от того, когда вызывается функция. Однако видимость переменной находится только внутри функции.

В вашем примере у вас есть функция, возвращающая адрес переменной static. Вы можете это сделать, однако вы должны понимать, что это использование не является потокобезопасным.Другими словами, все потоки, вызывающие функцию, получат одну и ту же переменную в одной и той же ячейке памяти, а не в их собственной версии переменной.

Вы также должны понимать, что если вы вернете адрес переменной static, вы также можете вызвать проблемы с реентракцией и рекурсивностью. Причина в том, что переменные в стеке обеспечивают повторное включение и рекурсию, поскольку каждый раз, когда функция вызывается, в стек добавляется новый кадр, поэтому каждый вызов функции имеет свой собственный стек стека, следовательно, свой собственный набор переменных.

Это известная проблема со старой strtok() функции в библиотеке Standard C, который использовал переменную внутри функции strtok() поддерживать состояние между вызовами с использованием NULL как строка адреса, где последний вызов strtok() кончили при разборе строка. Я видел проблему, когда функция, называемая strtok(), начала синтаксический анализ строки, а затем вызвала другую функцию, которая, в свою очередь, вызывала strtok(), чтобы начать синтаксический анализ другой строки. Результатом были некоторые действительно странные ошибки и поведение, пока причина не была выяснена.

Использование модификатора static в глобальной переменной в файле создает глобальную переменную, которая может использоваться несколькими функциями внутри файла. Однако, как и использование статического модификатора имени функции, переменная static будет обладать видимостью всего файла.

// .. top of a file of C source code 

static int aStaticInt = 0; // a static int that can be shared by all functions in the file but is visible only in the file 
int aNonStaticInt = 0; // a non static int that is visible outside of the file 

static int myStaticFunc (void) 
{ 
    // a function that is visible only within the file 
} 

int myNonStaticFunc (void) 
{ 
    // a function that is visible outside the file as well as inside the file 
} 
+0

Спасибо, сэр за подробное объяснение! – hbp

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