This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 编译器/C6000-CGT:CGT 8.3.x 中的 C++库不能提供可获取其地址的双精度 FMod (double、double)。 (至少为 pow、atan2、fmax & amp;fmin 也是如此)

Guru**** 2036780 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/887908/compiler-c6000-cgt-c-library-from-cgt-8-3-x-doesn-t-provide-a-double-fmod-double-double-whose-address-can-be-taken-same-goes-for-at-least-pow-atan2-fmax-fmin

器件型号:C6000-CGT

工具/软件:TI C/C++编译器

在我的应用中、我必须在函数指针中存储 fmod、pow、atan2、fmax 和 fmin 的双过载地址。 这在 CGT 8.3.x 中很难实现(我测试了8.3.0和8.3.6)。

尝试编译:

//最小示例
#include 
int main()
{
double works = fmod (1.0、3.0);
auto broken = static_cast (&FMod);
返回工作!=断开(1.0、3.0);
} 

使用命令:

$cgt_path/bin/cl6x -i$cgt_path/include overload_resolution.cpp 

产生以下输出:

"μ C/ti-CGT-C6000_8.3.6/include/libcxx/math.h"、第893行:~:静态断言失败、出现""
在"std:__2:__lazy_enable_if<的实例化期间检测到 ,std::__2:__promote <_A1, _A2, void>:在
编译"overy_resolution .cpp"时检测到"overy_resolution.cppp"的第6行中键入 fmod (_A1、_A2)[带_a1=double、_a2=double]"。

>>编译失败 

GCC、clang 和 MSVC 均可编译此最小示例、而不会出现任何问题。

查看断言、编译器决定在$cgt_path/include/libcxx/math.h 中定义的模板与在$cgt_path/include/math.h 中声明的 C 函数 double fmod (double、double)的匹配

进一步的分析表明、编译器得出这一结论是因为模板具有正常的 C++链接、而 C 函数具有'extern "C"链接:

//分析
extern "C" double foo (double、double)
{
return 0.0;
}

模板 
t3 foo (t1、t2)
{
static_assert (sizeof (t1)=0、"选择的错误过载");
return 1.0;
}

int main()
{
auto fp = static_cast (&foo);

返回 static_cast (fp (1.0、2.0));
} 

产生的

"OVERLOAD_RESolution.cpp"、第10行:错误:静态断言失败、并显示"Selected Wrong OVERLOAD (选择了错误的过载)"
在
"overy_resolution.cpp"编译中检测到的第16行"T3 foo (T1、T2)[ t1=double、t2=double、t3=double]"实例化期间检测到错误。

>>编译失败 

//分析
/*extern "C"*/ double foo (double、double)
{
返回0.0;
}

模板 
t3 foo (t1、t2)
{
static_assert (sizeof (t1)=0、"选择的错误过载");
return 1.0;
}

int main()
{
auto fp = static_cast (&foo);

返回 static_cast (fp (1.0、2.0));
} 

编译而不会出现问题。

我可以想象、模板与'extern "C"函数的匹配是正确的、但我希望有一个具有 C++链接的包装程序(类似于 float fmod (float、float))。  

在找出根本原因后、我获得了一个可以编译的权变措施:

//变通办法
#include 
extern "C"
{
auto cppfmod = static_cast (&FMOD);
}

int main()
{
double works = FMod (1.0, 3.0);
auto broken = cpfmod;
return works!= broken (1.0, 3.0);
} 
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您通知我们此问题、并做了大量工作来描述和分析此问题。

    我提交了 EXT_EP-9742条目 以进行调查。  欢迎您使用我签名中的以下链接进行操作。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Dennis:

    我们以前看到过这个问题、请参阅

    该标准目前规定、语言链接是该类型的一部分、因此 C++和 C 链接函数类型构成了不同的候选函数集以实现解析。 这在 C++ 14中没有变化。 7.5.1中的相关直接引述是:"两种具有不同语言链接的函数类型是不同类型的、即使它们在其他方面是相同的。"

    虽然大多数编译器放宽了这一要求、但我们过去没有、这样做可能会导致向后兼容性问题、因此我们必须仔细考虑是否要更改它。

    您可以在 extern "C"中为所需的函数类型换行 typedef、以使代码能够按预期进行编译、 但我认为这不是一个“好”的解决方案,因为 FMod 超载的目的是为不是双精度(*)(双精度、双精度)的呼叫提供备用候选。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    正如我在原始帖子中所说:

    [引用用户="Dennis Flori"]
    我可以想象、模板与'extern "C"函数的匹配是正确的、但我希望有一个具有 C++链接的包装程序(类似于 float fmod (float、float))。  

    [/报价]

    我最初的想法确实是要对'extern "C"过载提出一个问题、而不是被认为是更好的过载、但我注意到您也提到的标准中的确切一点、因此我决定对我的问题重新措辞。 :-) 我要做的(以及我认为应该能够做的)是获取 FMod 的双重过载地址。 这以前是可能的(至少达到 CGT 8.0.1)。  

    我认为所发生的情况如下:CGT 8.3 添加了对 C++14的支持、(自 C++11起)包含模板过载

    提升的 FMod ( Arithmic1 x,Arithmic2 y ); 

    在编译器中、此模板现在比更匹配

    extern "C" double fmod (double、double) 

    过载(请注意:在标准中、我找不到任何表明双 fmod 过载具有'extern "C"链接的内容、但在您的标题中、它具有)。

    但是、此模板过载不适用于双模板(双模板)。 double)、因此它具有一个 static_assert、该断言显式检查模板是否未实例化以实现标准中的其他过载之一:

    float 闪存(浮点 x,浮点 y);
    双精度 FMod ( double x, double y);
    long double fmod ( long double x, long double y); 

    然后、该 static_dassert 会中断我的最小示例的构建。

    就我所知、CGT8.3.x 的 math.h 基于 LLVM 的 math.h、但 LLVM 的编译器在语言链接和过载分辨率方面具有不同的行为、因此在尝试构建我的最小示例时、LLVM 没有相同的问题。  

    如果您同意可以使用 double fmod (double、double)的地址、我认为您有2个选项:

    1. 更改语言链接方面的过载分辨率行为
    2. 更新 math.h 以匹配编译器的行为

    我了解到、由于向后兼容性(虽然会增加与主要编译器的兼容性)、选项1不是首选项、因此将保留选项2。 我想删除 static_dassert 可能同样简单、但最好只添加一个显式双 fmod (double、double)包装器、正如我在原始帖子中建议的那样。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在进行一些初步研究时、这里显示的一条信息是、外部"C" Fmod 显然完全处于过载分辨率设置中、或者如果没有其他定义、则被放置在该设置中。

    extern "C" double fmod (double、double);
    int main ()
    {
    //解析、但我怀疑它不应该
    自动断开= static_cast (&FMod);
    返回断开(1.0、3.0);
    } 

    事实上、我们的编译器允许在需要诊断时从 extern "C"隐式转换为 extern "C++"。 这就是为什么我认为不应该使用上述代码的原因、以及为什么它会在 Fmod 存在时立即拾取外部"C++"模板定义。

    实际上、如果我们通过 enable_if 消除模板过载(定义取自 标头):

    模板 
    Typename std::enable_if
    <
    std::is 算术 <_A1>:::值&&
    std::is 算术 <_A2>:::值&&
    //确保大多数参数都是"双"的
    !(std::is 相同 <_A1, double>::value && std::ies_same <_A2, double>::值)、
    标准::__promote <_A1, _A2>
    ::键入
    fmod (_A1 _lcpp_x、_A2 _lcpp_y)
    {
    typedef 类型名 std:__promote <_A1, _A2>:键入__Result_type;
    static_assert (!(std:is_same <_A1, __result_type>:::值&&
    标准::IS 相同 <_A2, __result_type>::value))、"");
    返回::fmod ((__Result_type)__lcpp_x,(__Result_type)__lcpp_y);
    } 

    由于这种隐式转换、程序也会选择 extern "C"声明。 总之、我正在从手头的原始主题中挖掘出来。

    我认为、采用 FMod 的地址是实施 定义的。

    允许实现将 extern "C"和 extern "C++"视为不同的(对于符合标准的实现、必须这样做)。 根据 C++14标准的17.6.2.3第2段、还允许实现使用 extern "C"标记从 C 库导入的函数。

    他们建议使用 extern "C++"、但这对于以下产品是不可行的:

    • 关注链接的可执行文件的大小
    • 可以很好地将 C 和 C++对象链接在一起

    为导入的库函数使用 extern "C++"意味着将有一个从 C 和 C++调用的每个函数的不同副本。

    这并不意味着我们不会考虑本报告的更改、但我认为这不是一个错误、而是一个朝着更类似 LLVM/Gcc 的实现方向发展的请求。 我不认为我们反对这一点、但正如我之前所说的、由于向后兼容性、这是一项更大的任务。

    我相信您已经尝试了以下操作、但它允许您获得所需的行为:

    #include 
    extern "C"{使用 FMod_t = double (*)(double、double);}
    int main()
    {
    double works = fmod (1.0、3.0);
    auto broken = static_cast (&FMod);
    返回工作!=断开(1.0、3.0);
    }