LINUX.ORG.RU

Почему падает сборка без оптимизации?

 , ,


2

3

gcc 7.4 собирает пример с -O2 и ругается без оптимизации. gcc 4.8 собирает без ругани в обоих случаях. Где порылась собака и какое поведение правильное?

root@0d2ad7bc98a5:/build/src# cat a.c
#include <stdio.h>
inline void f(void)
{
        printf("wtf\n");
}
void g(void)
{
        f();
}
int main(void)
{
        f();
        return 0;
}
root@0d2ad7bc98a5:/build/src# gcc a.c
/tmp/ccOKVIbb.o: In function `g':
a.c:(.text+0x5): undefined reference to `f'
/tmp/ccOKVIbb.o: In function `main':
a.c:(.text+0x11): undefined reference to `f'
collect2: error: ld returned 1 exit status
root@0d2ad7bc98a5:/build/src# gcc a.c -O2
root@0d2ad7bc98a5:/build/src# gcc --version
gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Если убрать inline - сборка проходит. То, что компилятор к inline относится по-разному в зависимости от уровня оптимизации, я знаю. Но стулья ломать зачем?

Всё правильно тебе говорит компилятор.

https://gcc.godbolt.org/z/cnnCqW

Смотри

call    f

есть, а самой функции f() нет, так как она inline в С.

Чтобы всё работало нужно вынести inline функции в header файл, создать .c файл и в нём написать:

#include "header_with_inlines.h"

extern void f(void); // именно так, без тела функции, тело уже есть у inline, и возьмётся оттуда

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

fsb4000 ★★★★★
()
Ответ на: комментарий от fluorite

А почему для плюсов ок?

Потому что С++ и С разные языки.

https://en.cppreference.com/w/c/language/inline

https://en.cppreference.com/w/cpp/language/inline

Автор посмотри ещё: https://en.cppreference.com/w/c/language/inline

Там последний пример в точности то, что я написал выше.

extern inline и extern компилятор понимает одинакого, возможно даже лучше писать extern inline для понятности…

fsb4000 ★★★★★
()

Где-то включено форcирование inline-a. Скорее всего вопрос к майнтейнерам дистрибутива.

cvv ★★★★★
()
Ответ на: комментарий от fsb4000

последний пример в точности то, что я написал выше

Спасибо, понятно. Правда, нигде не написано, что поведение компилятора должно быть разным при -O2 и без него.

pinus_nigra
() автор топика

Можно сделать так:

inline void f(void) __attribute__ ((always_inline));
Этот момент недавно обсуждали тут

Максимально допустимый размер массива на стеке? (комментарий)

Максимально допустимый размер массива на стеке? (комментарий)

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от pinus_nigra

it’s unspecified whether the inline definition (if present in the translation unit) or the external definition is called

anonymous
()

Это ненормальное поведение. Выкинь данный компилятор и напиши мейнтейнерам.

К слову, откажись от такого использования inline (без extern), оно тебе не поможет в сишном коде никак. Как и любая статья из интернетов (а ты ведь именно так изучаешь сишку) про «оптимизацию».

anonymous
()

Так как тебе в лучших традициях лора советуют дикую чушь, отпишусь.

какое поведение правильное?

Зависит от стандарта.

Если убрать inline - сборка проходит.

Надо не убирать инлайн, а добавить к нему статик.

LamerOk ★★★★★
()

Просто в C inline хитро-сделанный в принципе. При этом в языке он официально с C99, а до этого его реализовывали иначе.

GCC использует стандартную семантику с -std=c99/-std=gnu99 (и с более поздними версиями), раньше использовал свою. В GCC 4.8 для C кода по умолчанию может быть -std=gnu89 с GNU версией inline, что объясняет разницу в поведении.

Рекомендую к прочтению эту заметку.

xaizek ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.