inline

Тема в разделе "Микроконтроллеры AVR", создана пользователем parovoZZ, 6 янв 2019.

  1. parovoZZ

    parovoZZ Гуру

    Пишу в заголовочном файле
    Код (C++):
    inline uint8_t my_function (void);
    В с файле
    Код (C++):
    inline uint8_t my_function (void)
    {
        return registr;
    }
    Пытаюсь вызвать в main
    Код (C++):
    a = my_function ();
    А с платформы говорят - вызов не задекларированной функции. Это что, inline из другого файла невозможен?
    Ну и второй вопрос - компилятор при однократном вызове такой функции догадается ее заинлайнить? А если многократный вызов? При каком уровне оптимизации это возможно?
     
    Последнее редактирование: 6 янв 2019
  2. SergeiL

    SergeiL Гуру

    Ну так и правильно говорит!
    my_function != myfunction
     
  3. parovoZZ

    parovoZZ Гуру

    пардон муа
     
  4. Asper Daffy

    Asper Daffy Гуру

    Тут сразу россыпь ошибок. Во-первых, если она в С файле, то при описании надо явно описать, что она на С, у функций на С++ другие имена (добавляются префиксы) и они не совпадают. Во-вторых, если она inline в C айле, то она не вызовется. iniline функция должна быть там, где её вызывают (ну, или через include включаться, что тоже самое).
     
  5. parovoZZ

    parovoZZ Гуру

    Так в студии в свойствах проекта указывается - Си или Cpp.

    И её даже компилятор по своему усмотрению не сможет заинлайнить? Но ведь это же так удобно - функции одного модуля держать в одном файле. А, получается, удобство разменивается неудобством со стороны кода((

    что, прям так
    Код (C++):
    #include my_function();
     
  6. Компилятор компилирует за раз только один .c или .cpp файл. Он в принципе не может сделать что-то с кодом, содержащимся в другом таком файле. Чтобы это работало, тело такой функции пишут в заголовочном файле и подставляют в каждый .cpp. Ключевое слово inline говорит компилятору, чтобы он не ругался на множественные определения одной и той же функции, вызванные таким подходом.
     
    parovoZZ нравится это.
  7. parovoZZ

    parovoZZ Гуру

    Получается, что такие однократно вызываемые функции как инициализация, необходимо писать в заголовке? Так её тогда вообще проще макросом оформить.
     
  8. parovoZZ

    parovoZZ Гуру

    Так может и вообще не нужны *.c файлы, если нет каких-то приватных функций. Всё писать в *.h файле?
     
  9. SergeiL

    SergeiL Гуру

    Если проект большой, зачем компилировать все файлы, включая то, что не менялось?
    Обычно компилируются только те файлы, которые изменялись, потом все собирается.
     
  10. Asper Daffy

    Asper Daffy Гуру

    Ну, если памяти много, - валяйте.
     
  11. SergeiL

    SergeiL Гуру

    А память то при чем???
     
  12. parovoZZ

    parovoZZ Гуру

    так наоборот. Сколько нужно кода для вызова такой функции:
    Код (C++):
    inline uint8_t my_function (void)
    {
        return registr;
    }
    А если её заинлайнить?
    Тоже самое с функцией инициализации. Зачем тратить время и место в памяти для её вызова, если она вызывается однократно?
     
  13. SergeiL

    SergeiL Гуру

    Не, тут говорят о другом:
    Не Нужны.png
     
  14. Asper Daffy

    Asper Daffy Гуру

    Ну, как причём?

    Для начала БЕЗ inline.

    Если функцию держать в inlude-файле и при этом не объявлять static, то линкер ругнётся на то, что она дважды определена. А вот если объявить static, то будет создана своя копия этой функции в каждом объектном файле, получаемом из .cpp, в который этот .h включается (ну, если линкер умный, то не в каждом, а только в тех, где функция реально используется) - но своя копия в каждом файле по-любому. Вот Вам и память.

    Вот пример. Я сделал проектик из трёх файлов. Сначала с обычной компоновкой (функция используется в двух файлах, определена в одном из них, а в .h файле только объявление

    Код (C++):
    //////////////////////////////////
    //
    // ФАЙЛ kaka.ino
    //
    #include "stupid.h"

    void setup() {
        stupid();
    }

    void loop() {
        stupid();
    }

    //////////////////////////////////
    //
    // ФАЙЛ stupid.h
    //
    #ifndef    STUPID_H
    #define    STUPID_H

    extern int stupid(void);

    #endif    //    STUPID_H

    //////////////////////////////////
    //
    // ФАЙЛ stupid.cpp
    //

    //////////////////////////////////
    //
    // Htpekmnfn rjvgbkzwbb
    //
    Скетч использует 1614 байт (5%) памяти устройства. Всего доступно 32256 байт.
    Глобальные переменные используют 186 байт (9%) динамической памяти, оставляя 1862 байт для локальных переменных. Максимум: 2048 байт.

    А теперь, не меняя ничего другого,просто перенес определение функции в include файл

    Код (C++):
    //////////////////////////////////
    //
    // ФАЙЛ kaka.ino
    //
    #include "stupid.h"

    void setup() {
        stupid();
    }

    void loop() {
        stupid();
    }

    //////////////////////////////////
    //
    // ФАЙЛ stupid.h
    //
    #ifndef    STUPID_H
    #define    STUPID_H

    static int stupid(void) {
        Serial.begin(9600);
        long i = 0;
        for (; i < 100; i++) {
            Serial.write(i);
        }
        for (; i < 200; i++) {
            Serial.write(i);
        }
        for (; i < 300; i++) {
            Serial.write(i);
        }
        for (; i < 100500; i++) {
            Serial.write(i);
        }
        return Serial.read();
    }

    #endif    //    STUPID_H

    //////////////////////////////////
    //
    // ФАЙЛ stupid.cpp
    //
    #include <arduino.h>
    #include "stupid.h"

    #include <arduino.h>

    static int stipdVariable = stupid();

    //////////////////////////////////
    //
    // Результат компиляции
    //
    Скетч использует 1792 байт (5%) памяти устройства. Всего доступно 32256 байт.
    Глобальные переменные используют 186 байт (9%) динамической памяти, оставляя 1862 байт для локальных переменных. Максимум: 2048 байт.

    Ну, и кто стырил 172 байта? Как корова языком слизнула.

    Вот при этом и память.

    С inline там ещё жёстче. Если функция маленькая - нет проблем, а если большая, он же её плодить будет в каждом месте вызова. inline - только для маленьких функций.
     
  15. parovoZZ

    parovoZZ Гуру

    Вы меня вообще читаете? Что я хочу заинлайнить - функции инициализации (большие функции), вызываемые ОДНОКРАТНО и очень маленькие функции. Я вот вынес такую маленькую функцию из *.с файла в макрос - 40 байт в плюс ушло. А вот маленькая функция с одним параметром, но вызываемая многократно, дала обратный эффект.
     
  16. parovoZZ

    parovoZZ Гуру

    Но мне здесь важен не размер кода, а скорость его выполнения. Памяти у меня много - аж 2 килобайта!
     
  17. Asper Daffy

    Asper Daffy Гуру

    Я то Вас читаю, а Вы сами? Я, вот, например отвечал на вполне конкретную фразу
    Я по наивности полагал, что "всё" означает именно "всё". Но если Вы пишете одно, а в голове держите другое, то я дико извиняюсь.

    И кстати, я подробно ответил на Ваш вопрос, не поленившись привести к объяснению ещё и пример программы (даже если и ошибся в трактовке вопроса). В ответ получил не "спасибо", а "Вы меня вообще читаете?". Впредь буду думать, отвечать на Ваши вопросы или просто Вас не читать.
     
  18. SergeiL

    SergeiL Гуру

    Честно говоря, не уверен я в корректности этого эксперимента.
    Еще наоборот понял бы, а так ...

    А где то есть объяснение этому?
     
  19. Совершенно пустыми микрооптимизациями занимаетесь, на самом деле. Из серьезной конторы за такую трату времени могут и попереть.
     
  20. parovoZZ

    parovoZZ Гуру

    да я с телефона сидел, там квотить вообще неудобно. А вообще отвечал на это
    Да никто меня с моего табурета не попрет!

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