Perilaku C # overflow untuk uint yang tidak dicentang

10

Saya telah menguji kode ini di https://dotnetfiddle.net/ :

using System;

public class Program
{
    const float scale = 64 * 1024;

    public static void Main()
    {
        Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)));
        Console.WriteLine(unchecked((uint)(ulong)(scale* scale + 7)));
    }
}

Jika saya kompilasi dengan .NET 4.7.2 saya dapatkan

859091763

7

Tetapi jika saya melakukan Roslyn atau .NET Core, saya mengerti

859091763

0

Mengapa ini terjadi?

Lukas
sumber
Para pemeran ulongsedang diabaikan dalam kasus terakhir sehingga terjadi dalam float-> intkonversi.
madreflection
Saya lebih terkejut dengan perubahan perilaku, itu sepertinya perbedaan yang cukup besar. Saya tidak akan mengharapkan "0" menjadi jawaban yang valid baik dengan rantai gips tbh.
Lukas
Bisa dimengerti Beberapa hal dalam spesifikasi diperbaiki di kompiler ketika mereka membangun Roslyn, sehingga bisa menjadi bagian darinya. Lihat output JIT pada versi ini di SharpLab. Itu menunjukkan bagaimana para pemain ulongmempengaruhi hasil.
madreflection
Sangat menarik, dengan contoh Anda kembali pada dotnetfiddle, keluaran WriteLine terakhir 0 di Roslyn 3.4 dan 7 pada .NET Core 3.1
Lukas
Saya juga mengkonfirmasi di Desktop saya. Kode JIT bahkan tidak terlihat sama sekali, saya mendapatkan hasil yang berbeda antara .NET Core dan .NET Framework. Trippy
Lukas

Jawaban:

1

Kesimpulan saya salah. Lihat pembaruan untuk detail lebih lanjut.

Sepertinya ada bug di kompiler pertama yang Anda gunakan. Nol adalah hasil yang benar dalam kasus ini . Urutan operasi yang ditentukan oleh spesifikasi C # adalah sebagai berikut:

  1. kalikan scaledengan scale, menghasilkana
  2. lakukan a + 7, menghasilkanb
  3. dilemparkan bke ulong, menghasilkanc
  4. dilemparkan cke uint, menghasilkand

Dua operasi pertama memberi Anda nilai float b = 4.2949673E+09f. Di bawah aritmatika floating-point standar, ini adalah 4294967296( Anda dapat memeriksanya di sini ). Itu cocok dengan ulongbaik-baik saja, jadi c = 4294967296, tapi itu persis satu lebih dari uint.MaxValue, jadi pulang pergi 0, karenanya d = 0. Sekarang, kejutan kejutan, karena aritmatika floating-point funky, 4.2949673E+09fdan 4.2949673E+09f + 7adalah nomor yang sama di IEEE 754. Jadi scale * scaleakan memberikan nilai yang sama dari floatseperti scale * scale + 7, a = bsehingga operasi kedua pada dasarnya adalah no-op.

Kompilator Roslyn melakukan (beberapa) operasi const pada waktu kompilasi, dan mengoptimalkan keseluruhan ekspresi ini 0. Sekali lagi, itulah hasil yang benar , dan kompiler diizinkan untuk melakukan optimasi apa pun yang akan menghasilkan perilaku yang sama persis seperti kode tanpa mereka.

Saya Dugaan adalah .NET 4.7.2 compiler yang Anda gunakan juga mencoba untuk mengoptimalkan ini, tetapi memiliki bug yang menyebabkannya untuk mengevaluasi para pemain di tempat yang salah. Tentu, jika Anda pertama kali scalemelakukan uintdan kemudian melakukan operasi, Anda mendapatkannya 7, karena scale * scalepulang pergi ke 0dan kemudian Anda tambahkan 7. Tapi itu tidak konsisten dengan hasil yang akan Anda dapatkan ketika mengevaluasi ekspresi langkah demi langkah saat runtime . Sekali lagi, akar penyebabnya hanyalah dugaan ketika melihat perilaku yang dihasilkan, tetapi mengingat semua yang saya nyatakan di atas, saya yakin ini adalah pelanggaran spesifikasi di sisi kompiler pertama.

MEMPERBARUI:

Saya telah melakukan kesalahan. Ada sedikit spesifikasi C # yang saya tidak tahu ada ketika menulis jawaban di atas:

Operasi titik-mengambang dapat dilakukan dengan presisi yang lebih tinggi daripada jenis hasil operasi. Sebagai contoh, beberapa arsitektur perangkat keras mendukung tipe floating-point "extended" atau "long double" dengan jangkauan dan presisi lebih besar daripada tipe double, dan secara implisit melakukan semua operasi floating-point menggunakan tipe presisi yang lebih tinggi ini. Hanya dengan biaya yang berlebihan dalam kinerja, arsitektur perangkat keras tersebut dapat dibuat untuk melakukan operasi titik-mengambang dengan ketelitian yang lebih rendah, dan alih-alih memerlukan implementasi untuk kehilangan kinerja dan presisi, C # memungkinkan tipe presisi yang lebih tinggi digunakan untuk semua operasi titik-mengambang . Selain memberikan hasil yang lebih tepat, ini jarang memiliki efek yang dapat diukur. Namun, dalam ekspresi bentuk x * y / z,

C # menjamin operasi untuk memberikan tingkat presisi setidaknya pada tingkat IEEE 754, tetapi tidak harus tepat itu. Ini bukan bug, ini fitur spek. The Roslyn compiler dalam haknya untuk mengevaluasi ekspresi persis seperti IEEE 754 menspesifikasikan, dan compiler lain dalam haknya untuk menyimpulkan bahwa 2^32 + 7adalah 7ketika dimasukkan ke dalam uint.

Saya minta maaf atas jawaban pertama saya yang menyesatkan, tetapi setidaknya kita semua belajar sesuatu hari ini.

V0ldek
sumber
Maka saya kira kita memiliki bug dalam compiler .NET Framework saat ini (saya baru saja mencoba di VS 2019 hanya untuk memastikan) :) Saya kira saya akan mencoba melihat apakah ada tempat untuk login bug, meskipun memperbaiki sesuatu seperti itu akan mungkin memiliki banyak efek samping yang tidak diinginkan dan mungkin diabaikan ...
Lukas
Saya tidak berpikir itu sebelum waktunya casting ke int, yang akan menyebabkan masalah yang lebih jelas dalam BANYAK kasus, saya kira kasus di sini adalah bahwa dalam operasi const itu tidak mengevaluasi nilai dan membuangnya sampai yang terakhir, artinya adalah bahwa alih-alih menyimpan nilai-nilai perantara dalam floats, itu hanya melewatkan itu dan menggantinya di setiap ekspresi dengan ekspresi itu sendiri
jalsh
@ jalsh Kurasa aku tidak mengerti tebakanmu. Jika kompiler hanya mengganti masing scale- masing dengan nilai float dan kemudian mengevaluasi semuanya saat runtime, hasilnya akan sama. Bisakah Anda menguraikan?
V0ldek
@ V0ldek, downvote adalah kesalahan, saya mengedit jawaban Anda sehingga saya bisa menghapusnya :)
jalsh
Dugaan saya adalah bahwa itu tidak benar-benar menyimpan nilai-nilai perantara dalam mengapung, itu hanya diganti f dengan ekspresi yang mengevaluasi f tanpa membuangnya ke float
jalsh
0

Intinya di sini adalah (seperti yang Anda lihat pada dokumen ) bahwa nilai float hanya dapat memiliki basis hingga 2 ^ 24 . Jadi, ketika Anda menetapkan nilai 2 ^ 32 ( 64 * 2014 * 164 * 1024 = 2 ^ 6 * 2 ^ 10 * 2 ^ 6 * 2 ^ 10 = 2 ^ 32 ) itu menjadi, sebenarnya 2 ^ 24 * 2 ^ 8 , yaitu 4294967000 . Menambahkan 7 hanya akan menambah bagian yang terpotong oleh konversi ke ulong .

Jika Anda berubah menjadi dua kali lipat , yang memiliki basis 2 ^ 53 , itu akan bekerja untuk apa yang Anda inginkan.

Ini bisa menjadi masalah run-time tetapi, dalam kasus ini, ini adalah masalah waktu kompilasi, karena semua nilai adalah konstanta dan akan dievaluasi oleh kompiler.

Paulo Morgado
sumber
-2

Pertama-tama Anda menggunakan konteks tidak dicentang yang merupakan instruksi untuk kompiler yang Anda yakin, sebagai pengembang, bahwa hasilnya tidak akan meluap jenis dan Anda ingin melihat tidak ada kesalahan kompilasi. Dalam skenario Anda, Anda sebenarnya tipe sengaja meluap dan mengharapkan perilaku yang konsisten di tiga kompiler berbeda yang salah satunya mungkin kompatibel jauh ke belakang dalam sejarah dibandingkan dengan Roslyn dan .NET Core yang baru.

Yang kedua adalah Anda mencampurkan konversi implisit dan eksplisit. Saya tidak yakin tentang kompiler Roslyn, tapi jelas .NET Framework dan .NET Core kompiler dapat menggunakan optimasi yang berbeda untuk operasi tersebut.

Masalahnya di sini adalah bahwa baris pertama dari kode Anda hanya menggunakan nilai / tipe floating point, tetapi baris kedua adalah kombinasi dari nilai / tipe floating point dan nilai / tipe integral.

Jika Anda membuat integer tipe floating point langsung (7> 7.0) Anda akan mendapatkan hasil yang sama untuk ketiga sumber yang dikompilasi.

using System;

public class Program
{
    const float scale = 64 * 1024;

    public static void Main()
    {
        Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale))); // 859091763
        Console.WriteLine(unchecked((uint)(ulong)(scale * scale + 7.0))); // 7
    }
}

Jadi, saya akan mengatakan berlawanan dengan apa yang dijawab V0ldek dan itu adalah "Bug (jika itu benar-benar bug) kemungkinan besar dalam Roslyn dan .NET Core kompiler".

Alasan lain untuk meyakini bahwa adalah hasil dari hasil perhitungan pertama yang tidak dicentang sama untuk semua dan itu adalah nilai yang melebihi nilai maksimal UInt32tipe.

Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale) - UInt32.MaxValue - 1)); // 859091763

Minus satu ada di sana saat kita mulai dari nol yang merupakan nilai yang sulit dikurangkan sendiri. Jika pemahaman matematika saya tentang overflow sudah benar, kita mulai dari angka berikutnya setelah nilai maksimal.

MEMPERBARUI

Menurut komentar jalsh

7.0 adalah dobel, bukan pelampung, coba 7.0f, masih akan memberi Anda 0

Komentarnya benar. Jika kita menggunakan float, Anda masih mendapatkan 0 untuk Roslyn dan .NET Core, tetapi di sisi lain menggunakan hasil ganda dalam 7.

Saya membuat beberapa tes tambahan dan segalanya menjadi lebih aneh, tetapi pada akhirnya semuanya masuk akal (setidaknya sedikit).

Apa yang saya asumsikan adalah .NET Framework 4.7.2 compiler (dirilis pada pertengahan 2018) benar-benar menggunakan optimasi yang berbeda dari .NET Core 3.1 dan Roslyn 3.4 compiler (dirilis pada akhir 2019). Optimalisasi / perhitungan yang berbeda ini murni digunakan untuk nilai konstan yang diketahui pada waktu kompilasi. Itu sebabnya ada kebutuhan untuk digunakanunchecked kata kunci karena kompiler sudah tahu ada overflow terjadi, tetapi perhitungan yang berbeda digunakan untuk mengoptimalkan IL akhir.

Kode sumber yang sama dan IL yang hampir sama kecuali instruksi IL_000a. Satu kompiler menghitung 7 dan 0 lainnya.

Kode sumber

using System;

public class Program
{
    const float scale = 64 * 1024;

    public static void Main()
    {
        Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)));
        Console.WriteLine(unchecked((uint)(scale * scale + 7.0)));
    }
}

.NET Framework (x64) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    // Fields
    .field private static literal float32 scale = float32(65536)

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 17 (0x11)
        .maxstack 8

        IL_0000: ldc.i4 859091763
        IL_0005: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_000a: ldc.i4.7
        IL_000b: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0010: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2062
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

} // end of class Program

Cabang penyusun Roslyn (Sep 2019) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [System.Private.CoreLib]System.Object
{
    // Fields
    .field private static literal float32 scale = float32(65536)

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 17 (0x11)
        .maxstack 8

        IL_0000: ldc.i4 859091763
        IL_0005: call void [System.Console]System.Console::WriteLine(uint32)
        IL_000a: ldc.i4.0
        IL_000b: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0010: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2062
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

} // end of class Program

Itu mulai berjalan dengan benar ketika Anda menambahkan ekspresi tidak konstan (secara default unchecked) seperti di bawah ini.

using System;

public class Program
{
    static Random random = new Random();

    public static void Main()
    {
        var scale = 64 * random.Next(1024, 1025);       
        uint f = (uint)(ulong)(scale * scale + 7f);
        uint d = (uint)(ulong)(scale * scale + 7d);
        uint i = (uint)(ulong)(scale * scale + 7);

        Console.WriteLine((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)); // 859091763
        Console.WriteLine((uint)(ulong)(scale * scale + 7f)); // 7
        Console.WriteLine(f); // 7
        Console.WriteLine((uint)(ulong)(scale * scale + 7d)); // 7
        Console.WriteLine(d); // 7
        Console.WriteLine((uint)(ulong)(scale * scale + 7)); // 7
        Console.WriteLine(i); // 7
    }
}

Yang menghasilkan "persis" IL yang sama oleh kedua kompiler.

.NET Framework (x64) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    // Fields
    .field private static class [mscorlib]System.Random random

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 164 (0xa4)
        .maxstack 4
        .locals init (
            [0] int32,
            [1] uint32,
            [2] uint32
        )

        IL_0000: ldc.i4.s 64
        IL_0002: ldsfld class [mscorlib]System.Random Program::random
        IL_0007: ldc.i4 1024
        IL_000c: ldc.i4 1025
        IL_0011: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32)
        IL_0016: mul
        IL_0017: stloc.0
        IL_0018: ldloc.0
        IL_0019: ldloc.0
        IL_001a: mul
        IL_001b: conv.r4
        IL_001c: ldc.r4 7
        IL_0021: add
        IL_0022: conv.u8
        IL_0023: conv.u4
        IL_0024: ldloc.0
        IL_0025: ldloc.0
        IL_0026: mul
        IL_0027: conv.r8
        IL_0028: ldc.r8 7
        IL_0031: add
        IL_0032: conv.u8
        IL_0033: conv.u4
        IL_0034: stloc.1
        IL_0035: ldloc.0
        IL_0036: ldloc.0
        IL_0037: mul
        IL_0038: ldc.i4.7
        IL_0039: add
        IL_003a: conv.i8
        IL_003b: conv.u4
        IL_003c: stloc.2
        IL_003d: ldc.r8 1.2
        IL_0046: ldloc.0
        IL_0047: conv.r8
        IL_0048: mul
        IL_0049: ldloc.0
        IL_004a: conv.r8
        IL_004b: mul
        IL_004c: ldc.r8 1.5
        IL_0055: ldloc.0
        IL_0056: conv.r8
        IL_0057: mul
        IL_0058: add
        IL_0059: conv.u8
        IL_005a: conv.u4
        IL_005b: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0060: ldloc.0
        IL_0061: ldloc.0
        IL_0062: mul
        IL_0063: conv.r4
        IL_0064: ldc.r4 7
        IL_0069: add
        IL_006a: conv.u8
        IL_006b: conv.u4
        IL_006c: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0071: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0076: ldloc.0
        IL_0077: ldloc.0
        IL_0078: mul
        IL_0079: conv.r8
        IL_007a: ldc.r8 7
        IL_0083: add
        IL_0084: conv.u8
        IL_0085: conv.u4
        IL_0086: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_008b: ldloc.1
        IL_008c: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0091: ldloc.0
        IL_0092: ldloc.0
        IL_0093: mul
        IL_0094: ldc.i4.7
        IL_0095: add
        IL_0096: conv.i8
        IL_0097: conv.u4
        IL_0098: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_009d: ldloc.2
        IL_009e: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_00a3: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2100
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

    .method private hidebysig specialname rtspecialname static 
        void .cctor () cil managed 
    {
        // Method begins at RVA 0x2108
        // Code size 11 (0xb)
        .maxstack 8

        IL_0000: newobj instance void [mscorlib]System.Random::.ctor()
        IL_0005: stsfld class [mscorlib]System.Random Program::random
        IL_000a: ret
    } // end of method Program::.cctor

} // end of class Program

Cabang penyusun Roslyn (Sep 2019) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [System.Private.CoreLib]System.Object
{
    // Fields
    .field private static class [System.Private.CoreLib]System.Random random

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 164 (0xa4)
        .maxstack 4
        .locals init (
            [0] int32,
            [1] uint32,
            [2] uint32
        )

        IL_0000: ldc.i4.s 64
        IL_0002: ldsfld class [System.Private.CoreLib]System.Random Program::random
        IL_0007: ldc.i4 1024
        IL_000c: ldc.i4 1025
        IL_0011: callvirt instance int32 [System.Private.CoreLib]System.Random::Next(int32, int32)
        IL_0016: mul
        IL_0017: stloc.0
        IL_0018: ldloc.0
        IL_0019: ldloc.0
        IL_001a: mul
        IL_001b: conv.r4
        IL_001c: ldc.r4 7
        IL_0021: add
        IL_0022: conv.u8
        IL_0023: conv.u4
        IL_0024: ldloc.0
        IL_0025: ldloc.0
        IL_0026: mul
        IL_0027: conv.r8
        IL_0028: ldc.r8 7
        IL_0031: add
        IL_0032: conv.u8
        IL_0033: conv.u4
        IL_0034: stloc.1
        IL_0035: ldloc.0
        IL_0036: ldloc.0
        IL_0037: mul
        IL_0038: ldc.i4.7
        IL_0039: add
        IL_003a: conv.i8
        IL_003b: conv.u4
        IL_003c: stloc.2
        IL_003d: ldc.r8 1.2
        IL_0046: ldloc.0
        IL_0047: conv.r8
        IL_0048: mul
        IL_0049: ldloc.0
        IL_004a: conv.r8
        IL_004b: mul
        IL_004c: ldc.r8 1.5
        IL_0055: ldloc.0
        IL_0056: conv.r8
        IL_0057: mul
        IL_0058: add
        IL_0059: conv.u8
        IL_005a: conv.u4
        IL_005b: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0060: ldloc.0
        IL_0061: ldloc.0
        IL_0062: mul
        IL_0063: conv.r4
        IL_0064: ldc.r4 7
        IL_0069: add
        IL_006a: conv.u8
        IL_006b: conv.u4
        IL_006c: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0071: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0076: ldloc.0
        IL_0077: ldloc.0
        IL_0078: mul
        IL_0079: conv.r8
        IL_007a: ldc.r8 7
        IL_0083: add
        IL_0084: conv.u8
        IL_0085: conv.u4
        IL_0086: call void [System.Console]System.Console::WriteLine(uint32)
        IL_008b: ldloc.1
        IL_008c: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0091: ldloc.0
        IL_0092: ldloc.0
        IL_0093: mul
        IL_0094: ldc.i4.7
        IL_0095: add
        IL_0096: conv.i8
        IL_0097: conv.u4
        IL_0098: call void [System.Console]System.Console::WriteLine(uint32)
        IL_009d: ldloc.2
        IL_009e: call void [System.Console]System.Console::WriteLine(uint32)
        IL_00a3: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2100
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

    .method private hidebysig specialname rtspecialname static 
        void .cctor () cil managed 
    {
        // Method begins at RVA 0x2108
        // Code size 11 (0xb)
        .maxstack 8

        IL_0000: newobj instance void [System.Private.CoreLib]System.Random::.ctor()
        IL_0005: stsfld class [System.Private.CoreLib]System.Random Program::random
        IL_000a: ret
    } // end of method Program::.cctor

} // end of class Program

Jadi, pada akhirnya saya percaya alasan untuk perilaku yang berbeda hanyalah versi kerangka kerja yang berbeda dan / atau kompiler yang menggunakan optimasi / perhitungan berbeda untuk ekspresi konstan, tetapi dalam kasus lain perilaku sangat sama.

dropoutcoder
sumber
7.0 adalah dobel, bukan pelampung, coba 7.0f, masih akan memberi Anda 0
jalsh
Ya, itu harus tipe floating point, bukan float. Terima kasih atas koreksi.
dropoutcoder
Itu mengubah seluruh perspektif masalah, ketika berhadapan dengan kelipatan presisi yang Anda dapatkan jauh lebih tinggi dan hasilnya yang dijelaskan dalam jawaban V0ldek berubah secara drastis, Anda mungkin hanya mengubah skala untuk menggandakan dan memeriksa lagi, hasilnya akan sama. ..
jalsh
Pada akhirnya ini adalah masalah yang lebih kompleks.
dropoutcoder
1
@alsh Ya, tapi ada flag compiler yang mengubah konteks yang diperiksa di mana-mana. Anda mungkin ingin semuanya diperiksa keamanannya, kecuali untuk jalur panas tertentu yang membutuhkan semua siklus CPU yang bisa didapat.
V0ldek