Какая разница между статическими inline void и void?

Я работаю на языке 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
}

Ответ 1

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

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

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

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

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


Посмотрев на образец кода, я бы предположил, что есть где-то определенное определение CGauss(), которое вызывается из файла file1.c, тогда как file2.c вызывает свою личную версию. Либо это, либо file1.c является #include ing file2.c. Это было бы противно.

Ответ 2

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 - это просто подталкивание компилятора к встроенным определенным функциям. Он может или не может на самом деле делать это в зависимости от собственного суждения.

Ответ 3

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

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

Встраивание

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

foo:
   /* some machine code */
   ret

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

  call <foo>

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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//Делаем материал, тем самым изменяя оригинальный программист.

Представьте, что вы пишете банковскую программу и оставите код уязвимым, чтобы кто-то мог изменить значение DEPOSIT, не меняя WITHDRAWL из другого банка в вашей рутине. Кто-то может прийти и написать отдельную программу, чтобы изменить это значение на 2 или 10, и создать деньги там, где их не было. Но если вы предшествуете коду, подпрограмме, методу или переменным с помощью STATIC Эти элементы не могут быть доступны, просмотрены и, что самое важное, изменены другой программой.

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

Включение 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;
}

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