我正在设计一个特定于域的CLI,在过去的几个星期里,我一直在研究各种角落案例,以确保我对所需要的内容有一个深刻的理解.
现在我正在研究类型构造.我正在考虑以下场景,我找不到太多信息:
class C
{
public static int Field = D.Field;
}
class D
{
public static int Field = C.Field;
}
class TestProg
{
static void Main()
{
Console.WriteLine( D.Field );
}
}
Run Code Online (Sandbox Code Playgroud)
这两个类都有标记beforefieldinit.
有趣的是,这个程序实际编译,并在MSCLR上运行,产生:
0
Run Code Online (Sandbox Code Playgroud)
所以在实践中发生的事情似乎是C..cctor构造中的触发点D被忽略,因为D构造已经开始了.但是,对我来说,这个程序看起来是无效的,在某种意义上说它是在完全构造之前C..cctor使用的东西.
许多人会指出上述场景毫无意义,但作为CLI的实现者,我担心这是因为我需要知道在类型初始值设定项中对循环引用有多大的自由度.
我在ECMA-335中可以找到的关于这一点的是:
如果标记为BeforeFieldInit,则类型的初始化方法在首次访问为该类型定义的任何静态字段时或之前执行.
在这种情况下,"执行时"这两个词会留下一些含糊之处,因为它们没有指定整个初始化程序是否必须执行或者执行是否必须简单地开始.
我发表评论暗指关于循环引用案例的CLI规范中的特定规则,但到目前为止,我还未能在ECMA-335中找到任何关于该问题的提及.
所以,我的问题是:
以上程序是否依赖于未定义的行为?还是未指明的行为?
如果我的CLR拒绝加载上述程序,它是否仍然符合要求?
如果没有,什么是关于类型构造循环引用确切的规则是什么?
是否有任何有效的,有用的设计模式可以在流量控制打折时导致程序类型初始化程序的有向图中的循环?
我正在考虑创建一个代表同步原语所有权的类,如下所示:
class CCriticalSectionLock
{
public:
CCriticalSectionLock( CCriticalSection &cs ) : cs( cs )
{ cs.Enter(); }
~CCriticalSectionLock()
{ cs.Leave(); }
private:
CCriticalSection &cs;
};
Run Code Online (Sandbox Code Playgroud)
这似乎是一种在函数期间获取所有权并确保即使存在多个退出点或例外也可以释放所有权的好方法.但是,它确实引发了一些关于编译器何时会对各种事物进行评估的细微问题.考虑以下用途:
int MyMethod( void )
{
not_locked(); // do something not under lock
CCriticalSectionLock myLock( someCriticalSection );
locked(); // do something under lock
return ...; // some expression
}
Run Code Online (Sandbox Code Playgroud)
据我所知,C++一生规则将保证not_locked()会被调用之前采取锁,并locked()同时持有锁会被调用.
但是,我不太清楚的是,何时返回的表达式将根据锁定析构函数的调用点进行计算.是否保证在析构函数之前计算表达式?我会这么认为,但我不是百分百肯定,如果不是,它可能导致非常微妙,间歇性,难以发现的错误!
Xamarin是一个完全提前编译.NET代码的系统(AOT),用于禁止数据执行的平台,因此不能拥有JIT.这个问题不是关于Xamarin,而是关于它的文档所做的断言.它在这里说:
通用虚方法支持是有限的,不可能静态地确定在所有情况下将调用哪种方法,因此编译器可能会忽略其中的一些方法.
我可能会弄错,但他们似乎暗示通过静态分析对这里可能发生的事情进行广泛的陈述,而不仅仅是他们选择在自己的软件中实施的内容.
正如Hans Passant恰当地指出的那样,他们给出的例子实际上并没有证明他们所指的问题,所以我把它排除在外.
因此,除了这些绝对棘手的特殊情况:
反射;
动态生成的代码(无论如何都是非法的);
涉及值类型的类型参数中的病态循环引用; 和
外国议会;
什么会使AOT编译器无法处理虚拟通用方法案例?
在研究CLI的内部时,我注意到类型签名可以指定数组边界(在编译时).例如,不要:
Byte[,]
我们可以有:
Byte[1...100,1...]
如果我没有弄错,就不可能在C#或C++/CLI中实际声明类似后者的类型.此外,ECMA-335表明:
VES为每个可区分的数组类型创建一个数组类型.通常,数组类型仅通过其元素的类型及其等级来区分.
公共语言规范(CLS)规定了许多限制,包括:
只需要一个项是一个数组的事实和数组的元素类型来区分重载.
因此,似乎对CLI的最低级别存在对编译时数组边界的支持,但在其他地方则不然.这让我想知道:
何时会在实践中创建/遇到包含此信息的类型签名?是否有.NET语言可以发出这种情况?编辑:有些语言可能通常使用基于单一的数组 - 但他们是否将其编码为类型签名?
哪里的CLI实际使用此信息,如果它是存在?(在我设计CLI实现时,我特别感兴趣.)
据我所知,任何数组都是使用newarr矢量的字节码指令或Array.CreateInstance一般情况创建的.这些机制都不接受数组本身的类型签名,因此创建它似乎无法使用此信息.
从理论上讲,此信息可用于通过内联高效的机器代码来计算地址来优化阵列访问.但是,ldelem朋友只能访问简单的向量; 多维数组访问需要一个方法调用,这让我觉得这样的优化可能不会发生.
我不得不认为这个机制有一些目的,为了让它成为一个国际标准,但我并没有真正看到它.
我正在编写在加载任何操作系统之前以实模式运行的代码。我的程序的一部分涉及将信息转储到视频显示,而标准 80x25 文本模式无法剪切它。
许多版本的 Windows 和其他操作系统在显示内核恐慌时似乎可以毫无困难地切换到更大的文本模式,我认为是 43 行。我知道更大的文本模式已经存在很长时间了,所以我希望至少有一种标准模式。
这里有一个相当大的 BIOS 视频模式列表:
http://www.columbia.edu/~em36/wpdos/videomodes.txt
不幸的是,相同的模式编号在芯片组之间的含义似乎有很大差异。
曾几何时,我似乎记得使用过一种名为 VESA BIOS 的东西以独立于设备的方式访问超级 VGA 图形模式,但我似乎还记得涉及必须加载的 DOS TSR。这不是一个选项这里因为 DOS 没有运行。
我正在寻找一种能够在最广泛的硬件上运行的模式,包括 VMware ESXi 中的虚拟视频适配器。更改模式的代码也需要紧凑,所以我希望一个简单的 Int 10h 就能做到这一点。
有任何想法吗?Windows 和 VMware 内核恐慌是如何发生的?
我正在编写一个程序,它将CIL字节码转换为C源代码以供机器使用.我担心由于转换为十进制和从十进制转换而导致的浮点常量不准确.在做了一些研究后,我发现C(但不是C++)应该能够接受浮点常量的十六进制表示法.
我决定尝试一下,但无论我尝试什么,MS VC9都会给我错误.这是我正在尝试的:
// Switches: /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FD /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TC
#include <tchar.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
double d = 0x1.0p+1; // error C2059
//double d = 0x1p+1; // doesn't work either
//double d = 0x1p1; // doesn't work either
//double d = 0x1.0p1; // doesn't work either
printf( "%f\n", d );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望这打印2,从1x2 ^ 1,但它给了我这个编译错误:
error C2059: syntax error …Run Code Online (Sandbox Code Playgroud) c floating-point floating-accuracy visual-studio-2008 visual-studio
是否可以通过托管代码抛出托管异常,但是调用堆栈中存在干预本机帧?
我在做这件事时遇到了麻烦.该应用程序是32位本机代码并托管MSCLR 2.0(但大多数代码是.NET 3.5.)
除非完成抛出,否则应用程序运行正常,并且当它抛出时究竟发生了什么取决于它运行的系统.
实际的应用程序非常复杂,所以至少在最初我会发布一些简单的概念代码只是为了说明.本机程序(我们将调用Native.exe)运行一个我们将调用的托管程序Managed.exe.某处内Managed.exe,用C#编写,如下:
class MyException : Exception {}
...
void OuterManaged()
{
MyObject.MyEvent += ( s, a ) =>
{
Console.WriteLine( "Throwing..." );
throw new MyException();
}
try
{
MyKernel.DoSomething();
Console.WriteLine( "Finished" );
} catch( MyException )
{
Console.WriteLine( "Caught" );
}
}
Run Code Online (Sandbox Code Playgroud)
MyKernel是我们将调用的混合C++/CLI程序集中定义的托管类Glue.dll. MyObject是另一个类的实例Glue.dll.那里的相关方法看起来像这样:
void DoSomething( void )
{
_pMyNativeKernel->DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
DoSomething是一个Native.exe虚拟调用的C++函数.总而言之,它最终会回归到一种Glue.dll可以提升的管理方法MyEvent …
我正在尝试构建logger1 ,它通过ElasticFusion从 Kinect 收集数据以进行离线 SLAM 。我正在 Windows 上构建。我正在尝试使用 VS10 构建 x64(我也有 VS12,但一些依赖项已预先配置到 VS10,因此为了简单起见,我正在使用它。)我正在使用 CMake 3.9.0。
我已经解决了大部分依赖关系,但 libusb 给我带来了麻烦。
我从 CMake 得到以下输出:
...
Checking for module 'libusb-1.0'
No package 'libusb-1.0' found
CMake Error at C:/Program Files/CMake/share/cmake-3.9/Modules/FindPkgConfig.cmake:412 (message):
A required package was not found
Call Stack (most recent call first):
C:/Program Files/CMake/share/cmake-3.9/Modules/FindPkgConfig.cmake:588 (_pkg_check_modules_internal)
CMakeLists.txt:12 (pkg_check_modules)
Run Code Online (Sandbox Code Playgroud)
通常,此时 CMake GUI 会以红色显示一些包含和库路径的新配置变量,以及一些非功能性默认值,例如ZLIB_INCLUDE_DIR-NOTFOUND我必须更改为实际路径并重新运行配置。
但是,在 的情况下libusb-1.0,GUI 中没有给我任何新的配置变量。我勾选了“高级”复选框,但所需的变量仍然没有显示。
我已经下载了一个预建的libusb-1.0.21,但是CMake不可避免地找不到它;这不是 *nix,其中库路径定义良好。我在文件服务器上有自己的目录结构来处理这些事情,所以 CMake 绝对无法找到东西,除非它询问我它们在哪里,但在本例中它没有这样做。
经过一番摸索,我在 Logger1's 中找到了一些参考资料CMakeLists.txt,如下:
find_package(PkgConfig)
pkg_check_modules(libusb-1.0 REQUIRED libusb-1.0) …Run Code Online (Sandbox Code Playgroud) 首先,在有人抱怨之前,我意识到在理论上完美的 C++ 代码的角度来看,内存模型是一个我不应该依赖的实现细节。然而,我更喜欢表现而不是纪律。
场景是这样的:我有一个地址空间区域,我已经告诉操作系统用我选择的文件来支持它——也就是说,该文件是内存映射的。如果我对 VMM 通常如何工作的理解是正确的,那么操作系统可能会非常懒惰地将页面加载到我的映射中,并且可能仅在页面实际被触摸时才这样做。
通常我可以忽略这个细节,但在这种特殊情况下,我将映射的数据发送到工作线程池中。如果我只是天真地将指向此缓冲区的指针传递给工作线程,那么当第一次触摸页面时,工作线程本身很有可能会遇到页面错误,这将导致工作线程阻塞,直到页面物理上由 VMM 加载。
工作池的设计使得它的线程在 I/O 上阻塞是非常糟糕的,而在作业中发送的线程可以容忍被阻塞。因此,我想让我的发件人线程首先接触映射的页面,以便页面错误会阻止它。
(我知道不能保证首先触摸页面会停止工作线程中的后续页面错误,但该程序仍然会在大多数时间处于最佳状态并始终正确。)
在 x86 汇编语言中,这很简单:
; get the page's address in ebx
mov al, Byte Ptr [ebx]
Run Code Online (Sandbox Code Playgroud)
不幸的是,它在 C 或 C++ 中并不是那么简单。一个简单的实现很简单:
char *pPage = ...;
char Dummy = *pPage;
Run Code Online (Sandbox Code Playgroud)
但是,这可能行不通,因为任何有自尊的优化器都会意识到代码什么都不做,只是简单地省略了它。
我们可以使用内联汇编,但这可能会严重削弱优化器。我们可以调用一个汇编语言函数来做到这一点,但是我们有(无可否认的小)函数调用开销是不必要的。
我们可以改为创建Dummy一个外部可见的变量,这会起作用,因为编译器不能假设赋值是无意义的。但是,这可能会导致 CPU 缓存线保持的争用,从而严重降低多核系统的性能Dummy。(更不用说,我们浪费了缓存行和访问权限。)
我也想过这样做:
char volatile *pPage = ...;
char Dummy = *pPage;
Run Code Online (Sandbox Code Playgroud)
我知道volatile关键字有两个保证:
编译器不会重新排序访问;和
编译器不会假设连续读取之间的值相同。
但是,这似乎并不能保证编译器即使不需要它也会读取该值。
有任何想法吗?