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

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

нашел объяснение static что меня смущает:

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

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

через тот же сайт, они объясняют встроенные функции

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

да???

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

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

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

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

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

5 ответов


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

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

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

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

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


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


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;
}

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

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


static ключевое слово

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

подстановкой

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

foo:
   /* some machine code */
   ret

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

  call <foo>

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

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

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

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

таким образом, вставка остается для компилятора в качестве опции оптимизации и с помощью ключевого слова, такого как C++'S inline, your встроенная директива или атрибут __GCC((inline)), вы только даете компилятору подсказку, что встраивание может стоить попробовать здесь.


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

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

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


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

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 и создать деньги там, где их не было. Но если вы предшествуете коду, подпрограмме, методу или переменным со статическими, эти элементы не могут быть доступны, просмотрены и, самое главное, изменены другим программа.

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

включение статики в 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;
}

и здесь защищены только переменные со статикой. 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;
}