Рассмотрим, как можно «выстрелить себе в ногу» на C# (и в целом в .NET).
Оказывается, такое можно сделать не только на C++.
Ниже представлен код, «играющийся» с типом bool (System.Boolean) и выводящий на экран 20 строк True или False.
Для первых десяти строк поведение детерминировано только для первой строки, а поведение для 2-10 строк зависит от реализации компилятора.
Код вполне самодокументированный, поэтому добавлю только, что на подобное поведение вполне можно наткнуться при вызове неуправляемых функций через P/Invoke, в случае их некорректного использования (на эту тему будет продолжение).
Оказывается, такое можно сделать не только на C++.
Ниже представлен код, «играющийся» с типом bool (System.Boolean) и выводящий на экран 20 строк True или False.
Для первых десяти строк поведение детерминировано только для первой строки, а поведение для 2-10 строк зависит от реализации компилятора.
Код вполне самодокументированный, поэтому добавлю только, что на подобное поведение вполне можно наткнуться при вызове неуправляемых функций через P/Invoke, в случае их некорректного использования (на эту тему будет продолжение).
//#define USE_POINTER_ARITHMETIC_FOR_UNSAFE_MODE
using System;
using System.Globalization;
using System.Runtime.InteropServices;
namespace ConsoleApplication
{
/// <summary>
/// Main Program Class
/// </summary>
static class Program
{
/// <summary>
/// Converts Byte Code to Boolean Value
/// </summary>
/// <param name="code">Byte Code</param>
/// <param name="unsafeMode">Use Unsafe Way to Convert</param>
/// <returns>Boolean Value</returns>
static bool ByteToBool(byte code, bool unsafeMode)
{
if (unsafeMode)
{
#if USE_POINTER_ARITHMETIC_FOR_UNSAFE_MODE
// This Code Needs The "/unsafe" Compiler Directive:
unsafe { return *(bool*)&code; }
#else
// This Code No Needs The "/unsafe" Compiler Directive:
return (new UnsafeBool() { Code = code }).Value;
#endif
}
return code != 0; // Safe Way
}
/// <summary>
/// Itz a "Funny" Bool Joke!
/// </summary>
static void BoolJoke(Action<string> output)
{
int row = 0;
Func<string> getNextRow = () => string.Format(NumberFormatInfo.InvariantInfo, "{0:00}: ", ++row);
for (int i = 0; i < 2; i++)
{
bool isUnsafeMode = i == 0;
output(isUnsafeMode ? "Unsafe Mode" : "Safe Mode");
bool b1 = true; // Internal Code: 1 (Implementation-Dependent, Undocumented)
bool b2 = ByteToBool(0xFF, isUnsafeMode); // Value is Invalid
bool b3 = ByteToBool(0xFE, isUnsafeMode); // Value is Invalid
output(getNextRow() + "b1 : " + b1);
output(getNextRow() + "b2 : " + b2);
output(getNextRow() + " b1 == b2: " + (b1 == b2));
output(getNextRow() + "!b1 == !b2: " + (!b1 == !b2));
output(getNextRow() + "b1 && b2 : " + (b1 && b2));
output(getNextRow() + "b1 & b2 : " + (b1 & b2));
output(getNextRow() + "b1 ^ b2 : " + (b1 ^ b2));
output(getNextRow() + "b1 && b3 : " + (b1 && b3));
output(getNextRow() + "b1 & b3 : " + (b1 & b3));
output(getNextRow() + "b1 ^ b3 : " + (b1 ^ b3));
output(null);
}
}
/// <summary>
/// Application Entry Point
/// </summary>
static void Main()
{
BoolJoke(Console.WriteLine);
Console.ReadKey(); // Press Any Key to Exit
}
}
/// <summary>
/// Unsafe Boolean Structure
/// </summary>
/// <remarks>
/// See https://msdn.microsoft.com/library/c8f5xwh7.aspx
/// See https://msdn.microsoft.com/library/eahchzkf.aspx
/// </remarks>
[StructLayout(LayoutKind.Explicit)]
struct UnsafeBool
{
/// <summary>
/// Boolean Value
/// </summary>
[FieldOffset(0)]
public bool Value;
/// <summary>
/// Boolean Value Internal Code
/// </summary>
[FieldOffset(0)]
public byte Code;
}
}