内联函数在不同的翻译单元中具有不同的编译器标志未定义的行为? [英] inline function in different translation units with different compiler flags undefined behaviour?

查看:139
本文介绍了内联函数在不同的翻译单元中具有不同的编译器标志未定义的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Visual Studio中,您可以为单个cpp文件设置不同的编译器选项.例如:在代码生成"下,我们可以在调试模式下启用基本的运行时检查.或者我们可以更改浮点模型(精确/严格/快速).这些只是示例.有很多不同的标志.

in visual studio you can set different compiler options for individual cpp files. for example: under "code generation" we can enable basic runtime checks in debug mode. or we can change the floating point model (precise/strict/fast). these are just examples. there are plenty of different flags.

一个内联函数可以在程序中定义多次,只要定义相同即可.我们将此函数放在标头中,并将其包含在多个翻译单元中.现在,如果不同cpp文件中的不同编译器选项导致该函数的编译代码略有不同,会发生什么情况?那么它们确实有所不同,我们的行为不确定吗?您可以将函数设为静态(或将其置于未命名的命名空间中),但更进一步,直接在类中定义的每个成员函数都是隐式内联的.这意味着如果这些cpp文件共享相同的编译器标志,则我们只能在不同的cpp文件中包含类.我无法想象这是真的,因为这基本上很容易出错.

an inline function can be defined multiple times in the program, as long as the definitions are identical. we put this function into a header and include it in several translation units. now, what happens if different compiler options in different cpp files lead to slightly different compiled code for the function? then they do differ and we have undefined behaviour? you could make the function static (or put it into an unnamed namespace) but going further, every memberfunction defined directly in a class is implicit inline. this would mean that we may only include classes in different cpp files if these cpp files share the identical compiler flags. i can not imagine this to be true, because this would basically be to easy to get wrong.

在不确定的行为领域,我们真的那么快吗?还是编译器会处理这种情况?

are we really that fast in the land of undefined behaviour? or will compilers handle this cases?

推荐答案

就标准而言,命令行标志的每种组合都将编译器转变为不同的实现.尽管能够使用其他实现产生的目标文件对实现很有用,但该标准并不强制要求这样做.

As far as the Standard is concerned, each combination of command-line flags turns a compiler into a different implementation. While it is useful for implementations to be able to use object files produced by other implementations, the Standard imposes no requirement that they do so.

即使没有内联,也应考虑在一个编译单元中具有以下功能:

Even in the absence of in-lining, consider having the following function in one compilation unit:

char foo(void) { return 255; }

以及以下内容:

char foo(void);
int arr[128];
void bar(void)
{
  int x=foo();
  if (x >= 0 && x < 128)
     arr[x]=1;
}

如果两个编译单元中的char是带符号的类型,则第二个单元中的x的值将小于零(从而跳过数组分配).如果在两个单元中均为无符号类型,则该值将大于127(同样跳过分配).但是,如果一个编译单元使用带符号的char,而另一个编译单元使用带符号的char,并且如果实现期望结果寄存器中的返回值以符号扩展或零扩展,则结果可能是编译器可以确定即使它拥有255,也不能大于127,或者即使它拥有-1,也不能小于0.因此,生成的代码可能会访问arr[255]arr[-1],结果可能会造成灾难性的后果.

If char was a signed type in both compilation units, the value of x in the second unit would be less than zero (thus skipping the array assignment). If it were an unsigned type in both units, it would be greater than 127 (likewise skipping the assignment). If one compilation unit used a signed char and the other used unsigned, however, and if the implementation expected return values to sign-extended or zero-extended in the result register, the result could be that a compiler might determine that x can't be greater than 127 even though it holds 255, or that it couldn't be less than 0 even though it holds -1. Consequently, the generated code might access arr[255] or arr[-1], with potentially-disastrous results.

尽管在许多情况下使用不同的编译器标记来组合代码应该是安全的,但标准并未尽力区分这种混合是安全的还是不安全的.

While there are many cases where it should be safe to combine code using different compiler flags, the Standard makes no effort to distinguish those where such mixing is safe from those where it is unsafe.

这篇关于内联函数在不同的翻译单元中具有不同的编译器标志未定义的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆