В чем разница между статической встроенной пустотой и пустотой?

Я работаю на языке C и модифицирую код, ранее написанный кем-то другим. Я борюсь с несколькими вещами, и я пытаюсь понять как можно больше о том, что происходит. Итак, как указано в моем вопросе, в чем разница между static inline void и void при создании функции? Заранее извиняюсь за длинный пост, но я хотел, чтобы вы знали, что я провел некоторое исследование, но не понимаю, что я нашел.

Я нашел объяснение static, которое меня смущает:

Статический спецификатор означает, что на функцию нельзя ссылаться из других файлов; то есть имя не экспортируется компоновщиком.

Читая это, я предполагаю, что ссылка на функцию отличается от вызова функции? Я предполагаю, что это потому, что эта функция вызывается из другого файла .c. Если это так, то что ссылается на функцию?

На том же веб-сайте они объясняют встроенные функции, и я не понимаю, что это значит.

Ключевое слово __inline указывает компилятору подставлять код в определение функции для каждого экземпляра вызова функции. Однако подстановка происходит только по усмотрению компилятора. Например, компилятор не встраивает функцию, если ее адрес занят или если она слишком велика для встраивания.

Хм???

Любая помощь приветствуется, и я еще раз прошу прощения за ужасно длинный пост.

Следующее находится в файле file1.c (с использованием общих имен, поскольку я не думаю, что это имеет значение)

COMPLEX cNoiseSample;
CGauss( &cNoiseSample, loopbackRadio->pState );

Следующее находится в файле file2.c

static inline void CGauss( COMPLEX * pcGauss, P_OS_UNIFORM_RAND_STATE pState )
{
    //code
}

person TZPike05    schedule 12.06.2012    source источник


Ответы (6)


static означает, что на него нельзя ссылаться из другой единицы компиляции (исходного файла). «Упомянутый» означает названный или иным образом упомянутый по имени, например. присваивается указателю на функцию.

inline — это подсказка компилятору о том, что код функции должен генерироваться встроенно в месте ее вызова, а не генерироваться как отдельная функция, к которой следует переходить. Обычно это делается из соображений производительности. Чтобы разобраться с цитатой Microsoft:

компилятор не встраивает функцию, если ее адрес занят или если она слишком велика для встраивания.

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

void означает, что функция не возвращает значение.


Посмотрев на ваш пример кода, я бы предположил, что где-то есть отдельное определение CGauss(), которое вызывается из file1.c, тогда как file2.c вызывает своя частная версия. Либо так, либо file1.c #includeing file2.c. Что было бы противно.

person Graham Borland    schedule 12.06.2012
comment
кроме того, inline необходимо для обеспечения соблюдения правила одного определения, когда функция определена в заголовке, включенном в разные единицы компиляции (или, по крайней мере, это имеет место для C++, не знаю точно эту деталь в C, я думаю, она будет будь таким же) - person rubenvb; 12.06.2012
comment
Ну, я думаю, я немного смущен, чем @Graham-Borland. Позвольте мне показать вам, почему: COMPLEX cNoiseSample; CGauss( &cNoiseSample, loopbackRadio->pState ); /*Этот код вызывается в одной точке исходного файла .c, а в другом исходном файле .c у меня есть это:*/ static inline void CGauss(COMPLEX * pcGauss, P_OS_UNIFORM_RAND_STATE pState) /*Прошу прощения за плохое форматирование в поле для комментариев, не знал, как еще это сделать.*/ - person TZPike05; 12.06.2012
comment
Это #include-ing it. В этом коде этого много. Имея дело, вероятно, с 200-250 исходными файлами и таким же количеством заголовочных файлов (надо любить работать с чужим кодом :)) Даже не думал о том, что функция #include является причиной, по которой она работает. - person TZPike05; 12.06.2012
comment
RE ПОЧЕМУ вы должны использовать static: Как правило, ваш код будет намного проще поддерживать, если вы свободно используете static. Это говорит сопровождающему, что вы можете изменить эту функцию, не нарушая ничего за пределами этого файла. На любой символ (функцию или переменную), который не является статическим, можно ссылаться буквально из любого места. Если вы пришли из ООП-языка (C++, Java и т. д.), подумайте о static функциях (или глобальных переменных) как о private, а обо всем остальном — как о public. Кроме того, использование функций static позволяет проводить более агрессивную оптимизацию компилятора. - person Brian McFarland; 12.06.2012
comment
Хотя static-функции не могут быть вызваны из других единиц перевода напрямую, вы можете передать указатель функции, который указывает на static функцию, в другую единицу перевода и вызвать эту функцию оттуда. - person 12431234123412341234123; 29.09.2017

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

inline — это оптимизация компилятора, которая в некоторых случаях ускоряет ваш код. Всякий раз, когда вы вызываете функцию, с ней связаны некоторые накладные расходы. Так что компилятор может полностью избавиться от функции, скопировав + вставив (почти) встроенный код.

Вот пример встраивания:

int dotproduct(int x1, int y1, int x2, int y2) {
    return multiply(x1,x2)+multiply(y1,y2);
}

inline int multiply(int a, int b) {
    return a*b;
}

Компилятор превратит это в:

int dotproduct(int x1, int y1, int x2, int y2) {
    return x1*x2+y1*y2;
}

Если вы хотите быть модным, вы также можете встроить функцию скалярного произведения;)

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

person tskuzzy    schedule 12.06.2012
comment
Спасибо @tskuzzy, встроенный текст теперь имеет больше смысла. - person TZPike05; 12.06.2012

Статическое ключевое слово

Определение статической функции C означает (как говорится в документах), что эта функция может быть доступна только из исходного файла, в котором она определена. Термин «ссылка» в этом смысле означает либо вызов этой функции, либо, например, получение указателя на нее. .

Встраивание

Обычно, когда вы пишете функцию на C, компилятор генерирует машинный код для этой функции:

foo:
   /* some machine code */
   ret

Каждый раз, когда вы вызываете эту функцию, компилятор вставляет такую ​​инструкцию, как

  call <foo>

в машинный код вызывающей стороны, что означает не что иное, как «перейти к foo, выполнить то, что вы там найдете, и когда вы встретите инструкцию ret, вернуться в это место».

Напротив, для встроенных функций компилятор не создает отдельную функцию foo(), а вместо этого вставляет машинный код для функции foo в каждый сайт вызова. При выполнении этого кода это имеет тот же эффект.

Так почему мы это делаем? Преимущество встроенного кода заключается в том, что вы экономите два перехода (вызов и соответствующий ret), что делает ваш код немного быстрее. Как недостаток, ваш код становится больше, потому что вы вставляете машинный код в каждый сайт вызова вместо того, чтобы иметь только одну копию вызываемой функции. Вот почему вы обычно встраиваете только небольшие функции.

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

Таким образом, встраивание остается для компилятора как вариант оптимизации, и, используя ключевое слово, такое как inline в C++, вашу директиву inline или __attribute((inline) в GCC), вы только даете компилятору подсказку, что inlining, возможно, стоит попробовать здесь.

person BjoernD    schedule 12.06.2012

Я хотел бы добавить ко всему вышесказанному, прежде чем читать вышеизложенное, важно понять, как работает программирование на С. Если вы просто пишете открытый код, например

Setup(){
    int MainVar
}

MyRoutine(){
   int myVar1;
   int myVar2;
   bool myVar3;
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

Затем любой может получить доступ к MyRoutine.myVar1 непосредственно из второй программы. Они могут изменить значение myVar2 (1. если оно не защищено, 2. если они знают, что оно есть, 3. если они знают, что оно делает) до того, как оно будет использовано в MyRoutine // Делать что-то, тем самым изменяя то, что оригинальный программатор предназначен.

Представьте, что вы пишете банковскую программу и оставили код уязвимым, чтобы кто-то мог изменить значение ДЕПОЗИТА, не изменяя СНЯТИЕ из другого банка в вашей подпрограмме. Кто-то другой мог прийти и написать отдельную программу, чтобы изменить это значение на 2 или 10 и создать деньги там, где их не было. Но если вы ставите перед кодом, подпрограммой, методом или переменными STATIC, эти элементы не могут быть доступны, просмотрены и, что наиболее важно, изменены другой программой.

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

Помещение Static в MyRoutine предотвратит выполнение MyRoutine из другой программы. Поскольку MyVars объявлены в MyRoutine, они не будут доступны из другой программы. Но если бы где-то в программе была объявлена ​​переменная MainVar, она была бы доступна.

Setup(){
    int MainVar  // This can be accessed from outside this code
}

static MyRoutine(){  // Because of static these vars are not
   int myVar1;
   int myVar2;
   bool myVar3;
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

А здесь защищены только переменные со static. myVar3 может быть прочитан из другого места, информируя другую подпрограмму о завершении обмена.

Setup(){
    int MainVar    // This can be accessed from outside this code
}

MyRoutine(){
   static int myVar1;  // This can NOT be accessed from outside this code
   static int myVar2;  // This can NOT be accessed from outside this code
   bool myVar3;        // This can be accessed from outside this code
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}
person KeyWizard    schedule 20.05.2018

static просто означает, что, по сути, функция для всех целей и задач «невидима» за пределами исходного файла, в котором она определена.

inline просит компилятор по существу подставить код вызова функции непосредственно в исходный код в каждом месте, где функция вызывается во время компиляции (например, замена вызова функции кодом функции) - однако это не гарантируется, он просто предлагает это вашему компилятору.

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

person mathematician1975    schedule 12.06.2012

Это так просто.

void* может возвращать пустой указатель (любая ссылка). Но void ничего вернуть не может.

Например:

1)

int x=7;

void *abc()    
{    
    return &x;    
}     

int main()    
{    
    printf("%d\n",*((int*)(abc())));    
}

Выход: 7

2)

int x=7;

void abc()    
{    
    return &x;    
}

int main()    
{    
    printf("%d\n",*((int*)(abc())));    
}

Это приведет к ошибке компиляции в printf("%d\n",*((int*)(abc())));

Потому что void ничего не может вернуть.

person pawanesh kumar pal    schedule 06.01.2019
comment
Пожалуйста, замените printf(%d\n,((int)(abc()))); to printf(%d\n,*((int)(abc())));, это опечатка - person pawanesh kumar pal; 06.01.2019