__inline из другой единицы компиляции

Тема в разделе "LANGS.C", создана пользователем cppasm, 3 апр 2009.

  1. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Привет.
    Появился вопрос по __inline.
    Скорее всего решения нету, но вдруг я чего-то не вижу.
    Код - чистый Си, без плюсов.
    Пишется библиотека для работы с определённым типом файлов.
    И в эти файлы надо писать различные сигнатуры.
    Функция выглядит примерно так:

    Код (Text):
    1. void write_sign1(FILE *f)
    2. {
    3.    putc(char1,f);
    4.    putc(char2,f);
    5. }
    Таких функций много. Поэтому хотел сделать инлайн.
    И тут появляется проблема - где писать тело этих функций.
    Если писать в *.С файле, который потом компилируется в lib - то эти функции наружу вообще не видны, что понятно.
    А если писать в заголовочном файле - то на первый взгляд всё отлично.
    Но если по каким-то причинам компилятор откажется инлайнить, полезут сообщения от линкера что функция объявлена много раз.
    Потому что заголовочный файл включается в несколько файлов приложения, использующего библиотеку.
    Пока кроме макроса ничего придумать не могу.
    Может кто чего подскажет?
    Вообще основной вопрос - можно ли заставить компилятор инлайнить функцию, объявленную в другом файле.
     
  2. Johnikum

    Johnikum Member

    Публикаций:
    0
    Регистрация:
    6 июн 2003
    Сообщения:
    97
    #ifndef _FILENAME_H_
    #define _FILENAME_H_

    ...
    ...
    ...

    #endif //_FILENAME_H_
     
  3. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    И чего? Ты проблему не понял.
    Вот тебе пример что это не поможет:

    Код (Text):
    1. // Header.h
    2. #ifndef _FILENAME_H_
    3. #define _FILENAME_H_
    4. void __inline write_sign(FILE *f)
    5. {
    6.   putc(123,f);
    7. }
    8. #endif
    Код (Text):
    1. // App_src1.c
    2. #include<Header.h>
    3. // some code here
    Код (Text):
    1. // App_src2.c
    2. #include<Header.h>
    3. // some code here
    Теперь компилируем эти два исходника (App_src1.c и App_src2.c) и собираем в приложение.
    Компилируются они отдельно, и код из Header.h будет подставлен в оба.
    А теперь при сборке линкер честно на тебя будет кричать - есть несколько функций с одинаковым именем.
     
  4. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Из справки MSVC:
     
  5. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    а где инлайн?
    Как правило инлайны и вставляют в хидеры.
    Что б твой пример заработал (хотя это очень корявый пример, и лучше никогда не помещать код в хидеры) необходимо добвать static в объявлении.
     
  6. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Пропустил. Исправил сообщение.
    Проблема в том, что __inline это просто рекомендация.
    И если компилятор всё равно решит не инлайнить, то будут повторные реализации.
    А static не вариант - всё равно будет куча версий одной функции.
    Y_Mur - нашёл такой ключ только в 2008 студии...
     
  7. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    cppasm
    как вариант можно попробовать 2008 линкер использовать совместно с другими компиляторами, правда там пишут что этот ключ заставляет линкер повторно вызывать компилятор для совместной работы.
     
  8. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    __forceinline (msvc only)?
     
  9. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Почитай на msdn :) Это лучше чем __inline, но всё равно не на 100%

     
  10. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Не ругется, что я делаю не так?
    Код (Text):
    1. test.h:
    2. void __inline write_sign(FILE *f)
    3. {
    4.   putc('t', f);
    5. }
    6.  
    7. test2.c:
    8. #include <stdio.h>
    9. #include "test.h"
    10.  
    11. extern "C" void test_func(FILE *f);
    12.  
    13. int __cdecl main(int argc, char* argv[])
    14. {
    15.     test_func(stdout);
    16.     write_sign(stdout);
    17.     getchar();
    18.     return 0;
    19. }
    20.  
    21. test1.c:
    22. #include <stdio.h>
    23. #include "test.h"
    24.  
    25. void test_func(FILE *f)
    26. {
    27.     write_sign(f);
    28. }
    Решит/не решит это еще не ясно. Скорее всего всё будет работать корректно.
    но зато они не будут торчать наружу.
     
  11. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Так и у меня не ругается.
    И не будет, до тех пор, пока компилятор будет послушно инлайнить.
    Так вот именно, что зависит от фазы луны.
    __inline не гарантирует что фукция будет встроена.
    А если она встроена не будет - полезут ошибки.
    Это да.
     
  12. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Мне кажется вы чего-то путаете
     
  13. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    В каком плане?
    Вот цитата MSDN, я уже выше приводил:
     
  14. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    cppasm
    Но это не означает, что полезут ошибки :))
     
  15. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Теоретически должны.
    Потому что реализация функции из заголовочного файла попадёт в каждый *.с, и будет дублирование имён на этапе сборки.
    В общем на всякий пожарный случай добавил к __inline ещё static - на случай если inline будет проигнорирован.
    На этом и остановлюсь наверное.
    Т.е. если __inline отработает, то всё нормально.
    А если нет - то функция будет продублирована в каждом модуле, но она будет внутренней.
    Немного не оптимально в плане размера, но это по сути редкий случай.

    А вообще компилятор умный зануда :)
    Вообще всё работает даже и без static.
    Можно насильно указать опцию /Ob0 - никакого инлайна (для проверки что будет).
    Так вот что интересно. Функция дублируется в каждый *.obj.
    Я смотрел список имён при помощи objconv.exe Агнера Фога.
    Во всех модулях она имеет одно и то же имя и атрибут public - т.е. торчит наружу.
    От cdecl функций ничем не отличается (в плане атрибутов в объектнике).
    Но линкер на неё не ругается. Почему - я так и не нашёл.
     
  16. diamond

    diamond New Member

    Публикаций:
    0
    Регистрация:
    21 май 2004
    Сообщения:
    507
    Адрес:
    Russia
    По стандартам ошибок быть не должно даже без static.
    Цитата из C99:
    Несколько внешних определений запрещено. Несколько инлайн-определений - пожалуйста.
     
  17. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    cppasm
    Не будет ошибок, так как реализация в одном файле - .h.
     
  18. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Да, но это в С99 - там ввели ключевое слово inline.
    Я в С89 компилирую, а там стандарт ничего не оговаривает.
    По старту С89 вообще нету __inline - это расширение, хотя и поддерживается практически всеми компиляторами.
    Но судя по тестам поведение аналогичное, просто в С99 его узаконили.

    Да что ты говоришь? И часто ты *.h файлы компилируешь?
    Заголовочный *.h подключается в *.c, его код просто подставляется препроцессором в *.c файл.
    И компилируется именно *.c файл.
    И если их много в проекте - в каждом будет реализация функции.
    Не веришь - возьми и проверь хотя бы мой пример без __inline:

    Код (Text):
    1. // Header.h
    2. #ifndef _SIGN_H_
    3. #define _SIGN_H_
    4. void write_sign(FILE *f)
    5. {
    6.   putc(123,f);
    7. }
    8. #endif
    Код (Text):
    1. // Sign1.c
    2. #include<stdio.h>
    3. #include<Header.h>
    4.  
    5. void print(void);
    6.  
    7. int main(void)
    8. {
    9.   FILE *f;
    10.   f=fopen("out.bin","wb");
    11.   if(!f) return 1;
    12.   write_sign(f);
    13.   print();
    14.   fclose(f);
    15.   return 0;
    16. }
    Код (Text):
    1. // Sign2.c
    2. #include<stdio.h>
    3. #include<Header.h>
    4. void print(void)
    5. {
    6.   printf("Hello from Sign2 source.\n");
    7. }
    cl /Ox /I"." Sign1.c Sign2.c
    И посмотри что тебе линкер скажет.
    А функция реализована в одном *.h
     
  19. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    cppasm
    Версию компилятора в студию.
     
  20. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    Да любой выбирай.

    VC++ 6.0
    VS 2005
    Intel C++ Compiler 10.1