LINUX.ORG.RU

Конфлит имён с библиотечным кодом

 


0

3

Вот есть строчка

const float gamma = 1.0;

Вылетает ошибка

src/../include/params.hpp:11:13: error: ‘const float gamma’ redeclared as different kind of symbol
 const float gamma = 1.0;
             ^~~~~
In file included from /usr/include/features.h:364:0,
                 from /usr/include/x86_64-linux-gnu/c++/6/bits/os_defines.h:39,
                 from /usr/include/x86_64-linux-gnu/c++/6/bits/c++config.h:507,
                 from /usr/include/c++/6/cstdio:41,
                 from src/four.cpp:1:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:274:1: note: previous declaration ‘double gamma(double)’
 __MATHCALL (gamma,, (_Mdouble_));
 ^

Что тут можно сделать? Кроме как переименовать свою переменную.

★★★★★

Не использовать using namespace, пользоваться namespace, особенно в библиотеках.

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

BRE i-rinat

Засунуть свои глобальные переменные в специальный namespace - это конечно тоже решение, спасибо.

Но меня больше интересует, как предотвратить попадание нежеланных библиотечных имён в область видимости.

В питоне есть from import и import as, а что в плюсах?

Crocodoom ★★★★★
() автор топика

Не создавать глобалки с такими именами, что не поймешь, глобалка это или нет. Можно, например, g_flGamma.

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

Ну это и есть переименовать. Или завернуть в namespace, как предложили выше, что по сути одно и то же. Этот подход я знаю, спасибо.

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

namespace cmath
{
#include <cmath>
};

Код выше у меня не компилируется...

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

Не слинкуется. Ты можешь пойти еще более худшим путем — обернуть в макрос:

#define gamma unuseful_gamma
#include <math.h
#undef gamma

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

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

Имелось в виду такое:

#include <iostream>
/* list anything you need below */
using std::cout;

algamest
()
#include <твой_хедер>

namespace твой_намеспейс
{
  const float gamma = 1.0;
}

...

gamma = ... /* из #include <твой хедер> */
твой_намеспейс::gamma = ...
BceM_IIpuBeT ★★☆☆☆
()
Ответ на: комментарий от Crocodoom

как предотвратить попадание нежеланных библиотечных имён в область видимости.

Сомневаюсь, что это возможно.

i-rinat ★★★★★
()
Ответ на: комментарий от a1batross

Это действительно работает для gamma, да!

Но не работает в других случаях :-(

#define sin unuseful_sin                                                        
#include <math.h>                                                               
#undef sin                                                                      
                                                                                
int sin = 1;
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:65:1: error: ‘__DECL_SIMD_unuseful_sin’ does not name a type
 __MATHCALL_VEC (sin,, (_Mdouble_ __x));
 ^
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:65:1: error: ‘__DECL_SIMD_unuseful_sinf’ does not name a type
 __MATHCALL_VEC (sin,, (_Mdouble_ __x));
 ^
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:65:1: error: ‘__DECL_SIMD_unuseful_sinl’ does not name a type
 __MATHCALL_VEC (sin,, (_Mdouble_ __x));
 ^

Впрочем идею я понял, может что-то найду/придумаю. А лучше взять готовое. По идее же у препроцессора gcc куча #pragma, может там что-то интересное найдётся.

Crocodoom ★★★★★
() автор топика
Ответ на: комментарий от E

Почистил все артефакты компиляции, всё равно нифига. А почему это вообще должно перебить библиотечную gamma?

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

Май бэд, я невнимательно читал ОП. Мне показалось, у тебя ошибки линковки.

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

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

Нельзя потому что C++. Не нравится - пиши в спортлото или Страуструпу.

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

Потому что это зависит от того, что внутри хедера. Но я бы не рекомендовал всн равно так делать.

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

А если так?

#define gamma my_gamma
const float gamma = ...;
#undef gamma
#include <cmath>
...
...
...
// Под конец хедера, например, или в самом .cpp файле:
#define gamma my_gamma

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

Постараюсь объяснить.

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

Например в Python это

  • from import
  • import as

В Haskell это

  • import (, ..)
  • import qualified
  • import as
  • import hiding

В плюсах же всё не так. Я вынужден локально обмазываться namespace в самом рядовом коде (не библиотечном!), если автор библиотеки не удосужился нормально использовать эти namespace у себя. Например так обстоит дело с сишными хедерами, из-за чего и весь сыр-бор начался (math.h). Но сишными хедерами проблема не исчерпывается.

Собственно, отвечая на вопрос: хочу найти решение, которое приблизит плюсы к современными языкам в отношении импорта имён.

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

То, что ты хочешь, сейчас нет, но будет в крестовых модулях. Модули может появятся в С++20.

Конкретно сейчас решения, кроме как обмазывания namespace, нет.

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

В питоне есть from import и import as, а что в плюсах?

Ничего.

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

Юзай <cmath>.

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

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

Да никто не воюет. Просто интересно пощупать возможности плюсового препроцессора. Он довольно мощный. Или им принципиально такое нельзя сделать? Почему?

Crocodoom ★★★★★
() автор топика
Ответ на: комментарий от E

Работает, конечно...

Но ты же понимаешь, что это и есть namespace и using, только для бедных сишников?

#define gamma my_gamma //namespace не завезли :3
const float gamma = ...;
#undef gamma
#include <cmath>
...
...
...
// Под конец хедера, например, или в самом .cpp файле:
#define gamma my_gamma //using не завезли :3
Crocodoom ★★★★★
() автор топика
Ответ на: комментарий от Crocodoom

Жабаскриптеру С и C++ никогда не дадутся. Они под тебя не прогнутся. Их нужно есть как позапрошлогоднюю картошку в мундире.

dzidzitop ★★
()
Последнее исправление: dzidzitop (всего исправлений: 2)
Ответ на: комментарий от Crocodoom

возможности плюсового препроцессора. Он довольно мощный. Или им принципиально такое нельзя сделать? Почему?

Посмотри его выхлоп на тестовых игрушечных заголовочных файлах. И тебе всё станет ясно.

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

какие нафиг модули, если большинство подключаемых библиотек написаны на C? А с плюсовыми библиотеками никаких проблем времени компиляции и так нет, если там в авторах нет макросных наркоманов.

dzidzitop ★★
()

приведите ВСЕ флаги компилятора (полную строку), в особенности интересно глянуть -std и дефайны включающие GNU расширения

IMHO трабл с gamma - чистая ГНУсь

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

Жабаскриптеру С и C++ никогда не дадутся.

Java-макаке тоже.

anonymous
()
Ответ на: комментарий от Crocodoom

Это действительно работает для gamma, да!

Но не работает в других случаях :-(

int sin = 1;

Странно, УМВР или я не понял суть проблемы.

#define sin nosin
#include <math.h>
#undef sin

int sin=0;

int main()
{
 return (int)cos(sin);
}
$ g++ -o test_math -lm test_math.cpp
$ ./test_math; echo $?
1
aureliano15 ★★
()
Ответ на: комментарий от aureliano15

MKuznetsov

А у меня твой код не собирается.

$ cat test_math.cpp 
#define sin nosin
#include <math.h>
#undef sin

int sin=0;

int main()
{
     return (int)cos(sin);
}
$ g++ -o test_math test_math.cpp
In file included from /usr/include/features.h:367:0,
                 from /usr/include/math.h:26,
                 from test_math.cpp:2:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:65:1: error: ‘__DECL_SIMD_nosin’ does not name a type
 __MATHCALL_VEC (sin,, (_Mdouble_ __x));
 ^
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:65:1: error: ‘__DECL_SIMD_nosinf’ does not name a type
 __MATHCALL_VEC (sin,, (_Mdouble_ __x));
 ^
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:65:1: error: ‘__DECL_SIMD_nosinl’ does not name a type
 __MATHCALL_VEC (sin,, (_Mdouble_ __x));
 ^

Версия конпелятора gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

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

Засунуть свои глобальные переменные в специальный namespace - это конечно тоже решение, спасибо.

Засунуть надо весь свой код в специальный namespace.

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

Просто интересно пощупать возможности плюсового препроцессора. Он довольно мощный.

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

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

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

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

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

А вообще у тебя странный подход. Ты упорно не хочешь убирать свое имя в namespace, но, почему-то, считаешь, что это просто обязан сделать автор библиотеки...

Решение для этой задачи уже придумано - модули. Но с ними есть несколько сложностей. Главная из них - собери 3-х людей, которые «знают» как нужно «правильно» реализовать модули и получишь 4 разных несовместимых мнения. Насколько я знаю, уже есть 2 реализации от MS и от clang и они разные (с корутинами повезло чуть больше, stackless корутины есть только от MS, а stackfull от boost, но они не в стандарте, пока).

anonymous
()
Ответ на: комментарий от anonymous

А вообще у тебя странный подход. Ты упорно не хочешь убирать свое имя в namespace, но, почему-то, считаешь, что это просто обязан сделать автор библиотеки...

Это не симметричная ситуация. Если авторы хотя бы двух используемых библиотек не позаботятся о namespace, и у этих библиотек найдутся общие имена идентификаторов, то я уже ничего не смогу сделать, чтобы использовать эти либы одновременно.

Поэтому да, обязан.

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

Версия конпелятора gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

Значит, это зависит от версии. У меня компилятор древнее:

gcc (Debian 4.9.2-10) 4.9.2

И там, кстати, ещё флаг -lm нужен, чтоб подключить математическую библиотеку, иначе даже в случае успешной компиляции не будет линковаться.

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

Версия конпелятора gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

Вот сейчас попробовал скомпилять на версии g++ 5.3.1 20160406 в Fedora 23. Получилось, если исправить

#define sin nosin

на

#define sin cos

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

И да, в версии gcc 5.3.1 библиотеку libm можно явно не подключать (т. е. флаг компиляции -lm для успешной сборки уже не нужен, хоть и не мешает).

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

Ну получается, что этот хак надо подбирать под содержимое хедера, а универсального хака нет. И внешние хедеры тоже имеют свойство меняться :) Так что да, бесполезно.

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

Так что да, бесполезно.

И к тому же ещё опасно. Лучше вообще по-возможности обходиться без хаков, используя штатные средства языка. А хаки оставить пижонам и тем, кому они действительно необходимы.

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

А у меня твой код не собирается.

а это не мой код :-)

у меня просто предположение, что ваш компилятор по умолчанию использует ГНУ-расширения и мерзкие фичи. Поставьте ему опцию -std=c++11 то есть задайте жёстко иную версию стандарта.

С обычным С,gcc и gamma происходят такие-же чудеса, если не задавать -std=c99 (или c89) - он по умолчанию творит ГНУсь

PS/ сделать вдруг идентификатор 'gamma' глобальным это за пределами добра и зла. Художники и музыканты негодуют.

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

Поставьте ему опцию -std=c++11 то есть задайте жёстко иную версию стандарта

Не-а, не помогает. Посмотрите:

$ cat dummy.cpp
#include <cstdio>
#include <cmath>

const float gamma = 0;

int main()
{
    printf("%f\n", gamma);
    return 0;
}
$ g++ -std=c++14 dummy.cpp
dummy.cpp:4:13: error: ‘const float gamma’ redeclared as different kind of symbol
 const float gamma = 0;
             ^
In file included from /usr/include/features.h:367:0,
                 from /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:39,
                 from /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:482,
                 from /usr/include/c++/5/cstdio:41,
                 from dummy.cpp:1:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:274:1: note: previous declaration ‘double gamma(double)’
 __MATHCALL (gamma,, (_Mdouble_));
 ^
dummy.cpp: In function ‘int main()’:
dummy.cpp:8:25: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘double (*)(double) throw ()’ [-Wformat=]
     printf("%f\n", gamma);
                         ^

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

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 

Но ничего пересобирать я, конечно, не буду:)

PS/ сделать вдруг идентификатор 'gamma' глобальным это за пределами добра и зла. Художники и музыканты негодуют.

В данном случае негодует матфизик... Ибо https://en.wikipedia.org/wiki/Gyromagnetic_ratio

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