Archive

Author Archive

รีวิวแว่น Carl Zeiss DriveSafe

drivesafe-00

ผมใช้แว่นนี้มาประมาณ 3 อาทิตย์แล้ว เลยอยากจะเขียนรีวิวสักหน่อย เหตุที่ได้เปลี่ยนแว่นเพราะทางบริษัทมีโควต้าค่าแว่นให้ 3,000 บาทในปีที่แล้ว บวกกับแว่นเก่าใช้งานมาได้ราว ๆ 7 ปีแล้ว เลยถือโอกาสนี้หาแว่นดี ๆ สักตัวใช้ และก็ได้มาจบที่ Carl Zeiss DriveSafe ตัวนี้ ที่ผมเลือกเลนส์ตัวนี้เพราะต้องขับรถกลางคืนเป็นประจำ

เลนส์ DriveSafe ตัวนี้ถูกออกแบบมาไว้สำหรับขับรถและใช้งานในชีวิตประจำวันทั่วไป คุณสมบัติหลัก ๆ ที่มีเลยคือ ตัดแสงรบกวนต่าง ๆ ทำให้เราสามารถมองเห็นอะไรบนถนนได้ง่ายขึ้น รูปข้างล่างคือภาพจาก Carl Zeiss ที่ใช้ในการโฆษณาเลนส์ตัวนี้

drivesafe-01

จากการใช้งานจริงสามอาทิตย์ รูปข้างบนไม่ได้โฆษณาเกินความจริงเลย รู้สึกได้ถึงความแตกต่างอย่างชัดเจนตั้งแต่ใส่ขับรถครั้งแรก ให้ความรู้สึกเหมือนได้ตาใหม่ การมองเห็นในชีวิตประจำวันก็ให้ความรู้สึกดีขึ้น รู้สึกภาพเนียนขึ้นกว่าแว่นเก่า ซึ่งอันหลังนี้น่าจะเป็นผลมาจากคุณภาพเลนส์ของ Carl Zeiss เอง ไม่น่าจะมาจากความสามารถของ DriveSafe

ทาง Carl Zeiss ได้โฆษณาด้วยว่าช่วยให้มองเห็นในยามฝนตกได้ดีขึ้นด้วย รูปด้านล่างคือภาพที่ใช้ในการโฆษณา

drivesafe-02

จากการใช้งานจริง ก็เหมือนในภาพเลย แต่ผมไม่รู้ว่ามันแตกต่างจากแว่นเก่าแค่ไหนเพราะมันเปรียบเทียบค่อนข้างยากนอกเสียจากจะเอาแว่นเก่าเตรียมไว้ในรถแล้วรอสลับตอนฝนตกเลย

ส่วนข้อเสียก็ใช่ว่าจะไม่มี เพียงแต่มันเล็กน้อยมากสำหรับผม ข้อเสียที่ว่านั้นคือ บางทีมันจะมีแสดงสะท้อนจากด้านหลังเลนส์ ทำให้เรามองเห็นแสงที่มาจากข้างหลังเราได้ ส่วนใหญ่จะเกิดกับหลอดไฟ แต่มันเล็กน้อยมาก เพราะมุมมองต้องตรงจริง ๆ เราถึงจะเจอข้อเสียนี้ ไม่ได้เกิดขึ้นตลอดเวลา และแสงสะท้อนก็ไม่ได้มากด้วย เป็นแค่จุดเล็ก ๆ ในเลนส์ ถ้าเทียบกับคุณภาพอื่น ๆ ของตัวเลนส์แล้วถือว่าเป็นเรื่องเล็กน้อยมาก

โดยรวมแล้วผมพอใจกับเลนส์ตัวนี้มาก สำหรับคนที่กำลังมองหาแว่นใหม่และต้องขับรถกลางคืนเป็นประจำ และสามารถจ่ายค่าแว่นในหลักสองหมื่นกว่าบาทได้อย่างไม่ลำบาก ผมแนะนำเลนส์ตัวนี้เลย มันจะทำให้คุณรู้สึกเหมือนคุณได้ตาใหม่ ราคาที่ผมได้มาอยู่ที่ราวๆ 16,000 บาท (ราคากรอบที่ผมเลือกอยู่ที่ราว ๆ 8,000 บาท) แต่ร้านแจ้งมาว่าราคาเต็มอยู่ที่สองหมื่นต้น ๆ เหตุที่ผมได้ราคานี้เพราะตอนแรกทางร้านเข้าใจผิดว่าเป็นเลนส์อีกตัวหนึ่ง แต่พอทางร้านติดต่อไปยัง Sale ของ Carl Zeiss แล้วพบว่ามันคนละตัวกันกับที่ทางร้านเข้าใจ ทางร้านก็เลยให้ราคานี้กับผมแทนราคาเต็ม ราคานี้เป็นราคาของ Index 1.6 (ตัวเลขนี้ยิ่งสูงเลนส์ยิ่งบาง) และเป็นเลนส์แบบ PhotoFusion ซึ่งช่วยให้แว่นเปลี่ยนเป็นสีดำเวลาโดดแดด ผมไม่แน่ใจว่าถ้าตัด PhotoFusion ออกและลด Index ลงราคาจะเหลือเท่าไหร่

ผมไม่รู้ว่าที่ไหนมีขายบ้าง ร้านที่ผมไปซื้อชื่อร้าน FOR EYES ที่ฟิวเจอร์พาร์ครังสิต น่าจะอยู่ที่ชั้น 1 ไม่ก็ชั้น 2 ซึ่งทางร้านโฆษณามาว่าเป็น Authorized Reseller ของเลนส์ Carl Zeiss เลยทีเดียว ซึ่งอันนี้ผมก็ไม่รู้ว่าจริงรึเปล่า แต่ดูจากภายในร้านแล้วคิดว่าน่าจะจริง เพราะห้องวัดสายตามีการ Paint กำแพงเป็นภาพของ Carl Zeiss ขนาดใหญ่อยู่ด้วย

อันนี้คือสเปคเลนส์ของผม

drivesafe-03

Categories: Eyes, Health Tags: , ,

ว่าด้วยโรค FIP ในแมว

2016/02/06 1 comment

โรค FIP (Feline infectious peritonitis) ในแมวนั้นถือเป็นหนึ่งในโรคที่อันตรายมากสำหรับแมว หากเกิดขึ้นแล้วโอกาสรอดแทบจะเป็นศูนย์ สาเหตุของโรคนี้เกิดจากไวรัสที่ชื่อว่า Feline coronavirus (FCoV) ซึ่งไวรัสตัวนี้จะมีอยู่สองชนิด ชนิดแรกมีชื่อว่า Feline enteric coronavirus (FECV) ซึ่งไวรัสตัวนี้จะไม่ก่อให้เกิดโรคร้ายแรง ส่วนชนิดที่สองมีชื่อว่า Feline infectious peritonitis virus (FIPV) ซึ่งเป็นตัวที่ก่อให้เกิดโรค FIP

โรค FIP นั้นจะมีอยู่สองแบบ แบบแรกคือแบบเปียก แบบเปียกจะก่อให้เกิดการสะสมของน้ำในช่องท้องของแมว สามารถสังเกตได้ง่าย ส่วนแบบที่สองคือแบบแห้ง ซึ่งจะไม่มีการสะสมของน้ำในช่องท้อง สาเหตุของโรค FIP นั้นเกิดจากการอักเสบของเนื้อเยื่อภายในเนื่องจากการติดเชื้อไวรัส FIPV

ไวรัส FIPV ที่เป็นสาเหตุของโรค FIP นั้นเกิดจากการกลายพันธุ์ของไวรัส FECV ซึ่งโอกาสเกิดจะขึ้นอยู่กับจำนวนของไวรัส FECV ที่มีอยู่ในตัวแมว ยิ่งมีมาก โอกาสเกิดก็ยิ่งมีสูง รวมถึงการสัมผัสกับไวรัสบ่อยๆด้วย จำนวนของไวรัส FECV ที่มากขึ้นอาจจะเกิดจากร่างกายที่อ่อนแอ หรือภูมิคุ้มกันต่ำ อาจจะเนื่องจากโรคอื่น เช่น ลูคีเมียในแมว หรือเอดส์แมว

การติดเชื้อไวรัส FECV นั้นเกิดขึ้นได้ง่ายมาก การสัมผัสเพียงครั้งเดียวสามารถทำให้ติดเชื้อไวรัสได้ในทันที ซึ่งการติดต่อของไวรัส FECV นั้นติดต่อผ่านทางอุจจาระของแมวตัวที่มีเชื้อนี้อยู่ ซึ่งแมวที่ติดเชื้อตัวนี้นั้นจะมีผลเกิดขึ้นได้สามทางคือ ติดเชื้อไวรัสตัวนี้ถาวรตลอดชีวิต หรือภูมิคุ้มกันสามารถกำจัดไวรัสทิ้งได้หมด แต่สามารถติดซ้ำได้อีกในอนาคต หรือมีภูมิต้านทานไวรัสตัวนี้ตลอดชีวิต หากแม่แมวมีเชื้อไวรัสตัวนี้อยู่ ลูกที่คลอดออกมาจะมีภูมิคุ้มกันไวรัสตัวนี้อัตโนมัติ แต่ภูมิคุ้มกันตัวนี้จะหายไปเมื่ออายุได้ประมาณเดือนหนึ่ง

ปุจจุบันยังไม่มีวัคซีนสำหรับป้องกัน FIPV ส่วนวัคซีนสำหรับป้องกัน FECV นั้นก็ใช้การได้ยากมาก เนื่องจากแมวตัวที่ได้รับวัคซีนจะต้องยังไม่มีเชื้อ FECV อยู่วัคซีนถึงจะได้ผล ซึ่งแมวทั่วโลกเกือบทั้งหมดมีไวรัสนี้อยู่

การลดความเสี่ยงโรค FIP ที่ได้ผลดีที่สุดคือ ลดจำนวนแมวที่เลี้ยงไว้ให้มากที่สุด จำนวนยิ่งน้อยโอกาสเกิดยิ่งลดต่ำ พร้อมทั้งเลี่ยงการทำให้ร่างแมวแมวอ่อนแอ ลดการสัมผัสกับแมวตัวอื่นทั้งทางตรงและทางอ้อม เช่น ไม่เล่นกับแมวตัวอื่น ไม่พาแมวออกไปเล่นกับตัวอื่น ถอดรองเท้าไว้ในที่ๆแมวเข้าไม่ถึง เนื่องจากเราอาจจะไปเหยียบอุจจาระแมวตัวอื่นที่มีไวรัส FECV เข้า

Categories: Cats, Pet

ประเภทของ Object ใน Java Virtual Machine และ Common Language Runtime

ใน Java Virtual Machine (JVM) และ Common Language Runtime (CLR) นั้น จะมี Type อยู่สองประเภทคือ Value Type และ Reference Type ซึ่ง Value Type จะเป็น Type ที่ Object จะเกิดการ Copy ตัวมันเองเมื่อมีการ Assign ตัวมันให้กับตัวแปรอื่น ส่วน Reference Type จะเป็น Type ที่ Object อาศัยอยู่บน Heap เท่านั้น ซึ่งต้องใช้ new ในการสร้างขึ้นมา

ใน JVM นั้น เราไม่สามารถสร้าง Value Type เพิ่มได้ ต้องใช้อันมี่ทีอยู่แล้วเท่านั้น ซึ่งแตกต่างจาก CLR ที่เราสามารถสร้าง Value Type เพิ่มได้ ทำให้ CLR มีข้อได้เปรียบอยู่หลายอย่าง เช่น

  • Performance ที่เพิ่มขึ้น เนื่องจาก Value Type ไม่จำเป็นต้องจอง Memory บน Heap
  • ติดต่อกับ Native Code ได้ง่ายขึ้น เนื่องจาก Type ใน Native Code จะเป็น Value Type

Object ที่เป็นชนิด Value Type นั้นสามารถแปลงเป็น Reference Type ได้ด้วยการ Wrap ไว้ใน Object ที่เป็น Reference Type อีกทีหนึ่ง ซึ่งการ Wrap นี่จะเรียกว่า “Boxing” ส่วนการแปลงกลับมาเป็น Value Type อีกครั้งจะเรียกว่า “Unboxing”

การ Boxing นั้น ใน C# จะสามารถ Assign ตัว Object ที่เป็นประเภท Value Type ใส่ตัวแปรที่เป็นคลาส System.Object ได้ทันที การ Unboxing นั้นก็เหมือนกัน สามารถ Cast กลับมาได้ทันที ส่วน Java นั้นเราจำเป็นต้องใช้คลาสที่มีมาให้อยู่แล้ว เช่น java.lang.Integer สำหรับ Wrap ตัว Object ที่เป็นชนิด int

ว่าด้วยเรื่องของ Asynchronous I/O บน Unix และ Win32

Asynchronous I/O ที่ใช้กันส่วนใหญ่ในปัจจุบันจะมีอยู่สองแบบ คือ แบบเก่าที่เป็นแบบ Notify on Ready และแบบใหม่ที่เป็นแบบ Notify on Completion ซึ่งต่อไปนี้จะขอเรียกว่า NoR และ NoC

NoR นั้นได้ถูกคิดค้นขึ้นมาก่อน NoC สำหรับใช้บน Unix ในช่วงแรกๆ ส่วน NoC นั้นได้ถูกคิดค้นขึ้นมาสำหรับใช้กับ Windows NT ซึงถูกเรียกว่า Overlapped I/O (แต่ก็ยังคงรองรับ NoR)

NoR นั้นจะใช้การแจ้งเตือนเมื่อ I/O พร้อมที่จะทำงาน เช่น มีข้อมูลสำหรับอ่านแล้ว หรือมี Buffer ว่างสำหรับทำการเขียน ข้อดีคือ เขียนได้ง่ายกว่าแบบ NoC ส่วนข้อเสียคือ

  • จัดการกับ Error ที่เกิดขึ้นจากการเขียนได้ยากมาก เนื่องจากเราเขียนลง Buffer ของ Kernel ไม่ใช่การเขียนลง Device จริง
  • อ่านพร้อมกันมากกว่าหนึ่งเธรดลำบาก เนื่องจากต้องมีการ Synchronize เพื่อป้องกันไม่ให้เธรดอื่นเข้ามาอ่านในระหว่างที่อีกเธรดกำลังอ่านอยู่ ซึ่งก็ไม่ใช่วิธีที่ดีเพราะจะก่อให้เกิดการ Lock เกิดขึ้น

ส่วน NoC นั้นจะใช้การแจ้งเตือนเมื่อ I/O ทำงานเสร็จแล้ว เช่น เราสั่งอ่านข้อมูล เมื่อการอ่านเสร็จสิ้น ก็จะมีการแจ้งเตือนมาบอกว่าอ่านเสร็จแล้ว การเขียนก็เหมือนกัน เราสั่งเขียน เมื่อการเขียนเสร็จสิ้น ก็จะมีการแจ้งเตือนมาบอกว่าเขียนเสร็จแล้ว มีข้อดีคือ

  • ใช้ได้มากกว่าหนึ่งเธรด เนื่องจากมีการกำหนด Buffer ที่จะทำการอ่านหรือเขียนตอนสั่ง I/O พอ I/O ทำงานเสร็จสิ้น การแจ้งเตือนจะตกไปอยู่ที่เธรดไหนก็ได้ไม่จำเป็นต้องเป็นเธรดที่สั่ง I/O
  • จัดการกับ Error ที่เกิดขึ้นกับ Device ได้ง่าย เนื่องจากการแจ้งเตือนจะถูกส่งมาหลังจากทำงานเสร็จสิ้นหรือมี Error เกิดขึ้นเท่านั้น

ส่วนข้อเสียคือ

  • เขียนได้ยากกว่าแบบ NoR เนื่องจากต้องมีการจัดการกับ Buffer ที่ยังทำงานไม่เสร็จ
  • พอร์ต Code เก่าๆที่เขียนโดยใช้ NoR ได้ยาก เนื่องจากรูปแบบที่แตกต่างกัน

ใน Unix และ Unix-like ใหม่ๆนั้นส่วนใหญ่จะรองรับ NoC กันหมดแล้ว แต่บาง OS ก็ยังไม่สมบูรณ์ บวกกับแต่ละ OS มี API ที่แตกต่างกัน ทำให้หากต้องการเขียน Code ที่ใช้ NoC บนหลายๆ OS ที่เป็น Unix และ Unix-like นั้นจะยุ่งยากมาก เลยไม่ค่อยเป็นที่นิยม ทำให้ส่วนใหญ่ยังคงใช้แบบ NoR กันอยู่ ส่วนบน Windows NT นั้น I/O ทุกอย่างจะใช้ NoC ทั้งหมด แล้วค่อยทำแบบ Synchronous โดยขี่อยู่บน Asynchronous อีกทีหนึ่ง ซึ่งการรองรับ NoR บน Windows NT นั้นทำขึ้นมาเพียงเพื่อให้ API บางส่วนเกิดความเข้ากันได้กับฝั่ง Unix เท่านั้น

การ Embed Common Language Runtime 4.0 โดยใช้ Visual C++ ภาค 1

สิ่งที่ต้องมี

  • ความรู้ Visual C++
  • ความรู้เกี่ยวกับ Component Object Model (COM)
  • ความรู้เกี่ยวกับ Common Language Runtime (CLR) และเรื่องอื่นๆของ .NET Framework

ภาพรวม

Component สำหรับ Embed CLR นั้น หลักๆจะมีอยู่สามส่วน คือ

  1. ICLRMetaHost เป็น Interface สำหรับจัดการกับ CLR ทั้งหมดที่ติดตั้งอยู่ในเครื่อง เช่น ลิสเวอร์ชั่นที่ติดตั้ง
  2. ICLRRuntimeInfo เป็น Interface สำหรับจัดการกับ CLR เช่น Get พาธของแฟ้มที่ติดตั้ง CLR ตัวนั้น หรือสั่งโหลด CLR เข้ามาใน Process
  3. ICLRRuntimeHost เป็น Interface สำหรับจัดการกับ CLR ที่ถูกโหลดเข้ามาใน Process แล้ว เราจะสั่งรัน Common Intermediate Language (CIL) โดยใช้ Interface นี้

การ Embed นั้น งานหลักๆที่ต้องทำคือ

  1. เรียกฟังชั่น CLRCreateInstance เพื่อสร้าง Object ที่ Implement ICLRMetaHost
  2. ลิส CLR ที่ติดตั้งอยู่ในเครื่องทั้งหมดด้วย ICLRMetaHost::EnumerateInstalledRuntimes แล้วเลือกเวอร์ชั่นที่ต้องการจะ Embed หรือเรียก ICLRMetaHost::GetRuntime เพื่อระบุเวอร์ชั่นที่ต้องการได้เลย
  3. เรียก ICLRRuntimeInfo::GetInterface เพื่อโหลด CLR เวอร์ชั่นที่เลือกเข้ามาใน Process
  4. เริ่มการทำงานของ CLR ด้วยการเรียก ICLRRuntimeHost::Start
  5. รัน CIL ด้วย ICLRRuntimeHost::ExecuteInDefaultAppDomain

รายละเอียด

ก่อนอื่น ให้เรา Initialize COM สำหรับเธรดหลักโดยใช้ CoInitializeEx ก่อน ตัวอย่าง

hrResult = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY);

จากนั้น ให้เรียก CLRCreateInstance เพื่อที่จะ Get ข้อมูลของ CLR เวอร์ชั่นที่ต้องการ ตัวอย่าง

ATL::CComPtr pClrMetaHost;

hrResult = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast(&pClrMetaHost));

ต่อไปสิ่งที่เราจะทำก็คือ เลือก CLR เวอร์ชั่นที่ต้องการใช้งาน ตัวอย่างการเลือกเวอร์ชั่น 4.0

ATL::CComPtr pClrInfo;

hrResult = pClrMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, reinterpret_cast(&pClrInfo));

พารามิเตอร์แรกของ ICLRMetaHost::GetRuntime จะเป็นเวอร์ชั่นของ CLR ที่ต้องการ โดยชื่อจะต้องตรงกับชื่อแฟ้มที่อยู่ใน C:\Windows\Microsoft.NET\Framework
พอได้ ICLRRuntimeInfo มาแล้ว สิ่งต่อไปที่เราจะทำก็คือ โหลด CLR ตัวนั้นเข้ามาใน Process ตัวอย่าง

ATL::CComPtr pClr;

hrResult = pClrInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, reinterpret_cast(&pClr));

เมื่อ CLR ถูกโหลดเข้ามาใน Process แล้ว เราต้องเริ่มการทำงานของ CLR ตัวนั้นเสียก่อน ถึงจะสามารถรัน CIL ได้ ตัวอย่างการรัน CLR

hrResult = pClr->Start();

เมื่อทุกอย่างพร้อมแล้ว สิ่งที่เราจะทำต่อไปก็คือ รัน CIL ที่เขียนขึ้นด้วยโค๊ดของ C# ต่อไปนี้

using System.Windows.Forms;

namespace Putta.CLREmbedding
{
    public class Application
    {
        public static int Start(string commandLine)
        {
            return (int)MessageBox.Show(string.Format("Message from CIL World ! Application Command Line is: {0}", commandLine), "Message", MessageBoxButtons.OKCancel);
        }
    }
}

ตัวอย่างการรัน

hrResult = pClr->ExecuteInDefaultAppDomain(L"Application.dll", L"Putta.CLREmbedding.Application", L"Start", pszCommandLine, &dwCilResult);

พารามิเตอร์แรกจะเป็นชื่อ Assembly ของ CIL ที่เราต้องการจะรัน พารามิเตอร์ที่สองจะเป็นชื่อคลาสของ Method ที่จะรัน ส่วนพารามิเตอร์ที่สามจะเป็นชื่อ Method ที่ต้องการจะรัน โดยต้องประกาศเป็นแบบ public static int และรับพารามิเตอร์เป็น string หนึ่งตัวเท่านั้น ส่วนค่าที่ Return จาก Method จะถูกเก็บไว้ใน dwCilResult

Project ตัวอย่าง

ดาวน์โหลดได้จาก ที่นี่

วิธีตรวจจับ Memory Leak โดยง่ายของ Visual C++

วิธีนี้จะตรวจจับได้เฉพาะ Memory ที่ Alloc โดยใช้ฟังชั่นของ CRT (C-Runtime) เท่านั้นนะคับ เช่น malloc, realloc, operator new ฯลฯ และจะต้องเป็น Debug Build เท่านั้น หากเป็น Release Build ตัวตรวจจับจะถูกถอดออกอัตโนมัติ ส่วน Memory ที่ Alloc โดยใช้ฟังชั่นนอกเหนือจากนั้น (เช่น HeapAlloc ของ Win32 API) จะไม่สามารถตรวจจับด้วยวิธีนี้ได้ โดยการตรวจจับจะรายงานผลตอนที่โปรแกรมจบการทำงานแล้วผ่านทาง Debug Message ซึ่งดูได้ด้วยโปรแกรม DebugView หรือช่อง Output ของ Visual Studio หาก Debug ใน Visual Studio

วิธีการคือ ให้เรียกฟังชั่น _CrtSetDbgFlag (ต้อง include crtdbg.h เข้ามาก่อน) แบบตัวอย่างด้านล่างตอนที่โปรแกรมเริ่มการทำงาน

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

ตัวอย่างการใช้งานใน DllMain

#include <crtdbg.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID /* lpReserved */)
{
	if (DLL_PROCESS_ATTACH == ul_reason_for_call)
	{
		DWORD dwResult, dwBufferSize;
		wchar_t *pszModuleName;

		// Enable C-Runtime memory leak reporter
		_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

		// Get Module Name
		pszModuleName = nullptr;
		dwBufferSize = MAX_PATH / 2;

		do
		{
			free(pszModuleName);
			pszModuleName = reinterpret_cast<wchar_t *>(malloc((dwBufferSize *= 2) * sizeof(wchar_t)));

			dwResult = GetModuleFileName(hModule, pszModuleName, dwBufferSize);
		} while (dwResult == dwBufferSize);

		PathStripPath(pszModuleName);

		g_pszModuleName = pszModuleName;

		// Init WTL
		_Module.Init(NULL, hModule);
	}
	else if (DLL_PROCESS_DETACH == ul_reason_for_call)
	{
		// Free allocated memory
		free(const_cast<wchar_t *>(g_pszConfigDirectory));
		free(const_cast<wchar_t *>(g_pszNppDirectory));
		free(const_cast<wchar_t *>(g_pszModuleName));

		// Terminate WTL
		_Module.Term();
	}

	return TRUE;
}

ตัวอย่างการรายงานผล

Categories: C, C++, Programming, Software Development Tags:

Performance ระหว่าง i++ และ ++i

คนเก่งหลายๆคน มักจะใช้ ++i แทนการใช้ i++ ใน for ลูป โดยคิดว่า มันทำงานเร็วกว่า i++ ซึ่งก็ไม่แปลกที่จะคิดแบบนั้น เพราะตัวผมเองก็เห็นคำตอบของชาวต่างชาติหลายคนบอกไว้แบบนี้เหมือนกัน แต่ในความเป็นจริงแล้ว บน Visual C++ มันไม่ต่างกันเลย

เมื่อ Visual C++ คอมไพล์ Code นี้

int _tmain(int argc, _TCHAR* argv[])
{
	for (int i = 0; i < argc; ++i)
		_tprintf(_T("%d"), i);

	return 0;
}

Code ที่ได้จะเป็น

	mov	DWORD PTR _i$5259[ebp], 0
	jmp	SHORT $LN3@wmain
$LN2@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	add	eax, 1
	mov	DWORD PTR _i$5259[ebp], eax
$LN3@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	cmp	eax, DWORD PTR _argc$[ebp]
	jge	SHORT $LN1@wmain
; Line 10
	mov	esi, esp
	mov	eax, DWORD PTR _i$5259[ebp]
	push	eax
	push	OFFSET ??_C@_15KNBIKKIN@?$AA?$CF?$AAd?$AA?$AA@
	call	DWORD PTR __imp__wprintf
	add	esp, 8
	cmp	esi, esp
	call	__RTC_CheckEsp
	jmp	SHORT $LN2@wmain

และเมื่อคอมไพล์ Code นี้

int _tmain(int argc, _TCHAR* argv[])
{
	for (int i = 0; i < argc; i++)
		_tprintf(_T("%d"), i);

	return 0;
}

Code ที่ได้จะเป็น

	mov	DWORD PTR _i$5259[ebp], 0
	jmp	SHORT $LN3@wmain
$LN2@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	add	eax, 1
	mov	DWORD PTR _i$5259[ebp], eax
$LN3@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	cmp	eax, DWORD PTR _argc$[ebp]
	jge	SHORT $LN1@wmain
; Line 10
	mov	esi, esp
	mov	eax, DWORD PTR _i$5259[ebp]
	push	eax
	push	OFFSET ??_C@_15KNBIKKIN@?$AA?$CF?$AAd?$AA?$AA@
	call	DWORD PTR __imp__wprintf
	add	esp, 8
	cmp	esi, esp
	call	__RTC_CheckEsp
	jmp	SHORT $LN2@wmain

สังเกตตรง

$LN2@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	add	eax, 1
	mov	DWORD PTR _i$5259[ebp], eax

จะเห็นว่ามันเหมือนกันเปะ

Categories: C, C++, Programming, Software Development Tags: