คอมไพเลอร์จะปรับอาร์กิวเมนต์ที่ไม่ได้ใช้ของฟังก์ชันคงที่ให้เหมาะสมหรือไม่

ฉันมีกลุ่มของฟังก์ชันที่ประกาศไว้ทั้งหมดเป็น static และ fastcall ส่วนใหญ่ใช้ตัวชี้ไปยังโครงสร้างที่รองรับบทบาทของ this ใน C++ ไม่มากก็น้อย ฟังก์ชั่นบางอย่างไม่ต้องการอะไรในโครงสร้าง แต่เพื่อความสม่ำเสมอฉันอยากจะส่งต่อตัวชี้ให้พวกเขาต่อไป คอมไพเลอร์จะสังเกตเห็นว่าไม่ได้ใช้อาร์กิวเมนต์และละเว้นการจัดสรรการลงทะเบียนหรือไม่


person cleong    schedule 12.01.2013    source แหล่งที่มา


คำตอบ (3)


ฉันเขียนโปรแกรมไร้สาระนี้เพื่อทดสอบสิ่งนี้ มันมีโค้ดไร้สาระอยู่ในฟังก์ชัน และเรียกมันหลายครั้งเพราะไม่เช่นนั้นคอมไพเลอร์ก็จะอินไลน์การเรียกใช้ฟังก์ชันทั้งหมด ทำให้การทดสอบไร้ประโยชน์ (มันเป็นการผสมผสานที่แปลกของ C และ C++ ฉันรู้ว่า.... รหัสโง่ ๆ แต่ก็ยังใช้งานได้เพื่อสาธิตปัญหา)

#include <stdio.h>
#include <vector>
#include <algorithm>

using namespace std;

struct demo
{
    int a;
    char ch;
};

static  void __fastcall func(struct demo* d)
{
    for(int i = 0; i < 100; i++) {
    std::vector<int> a;
    std::sort(begin(a), end(a));
    printf("THis is a test");
    printf("Hello world\n");
    }
}

int main()
{
  //  void*p = (void*)&func;
    struct demo d;
    func(&d);
    func(&d);
    func(&d);
    func(&d);
    func(&d);
    func(&d);
    func(&d);
    //printf((const char*)p);
}

ตามที่เขียนไว้ที่นั่นการเรียกใช้ฟังก์ชันคอมไพล์ดังนี้: -

    func(&d);
00F61096  call        func (0F61000h)  
    func(&d);
00F6109B  call        func (0F61000h)  
    func(&d);
00F610A0  call        func (0F61000h)  
    func(&d);
00F610A5  call        func (0F61000h)  
    func(&d);
00F610AA  call        func (0F61000h)  
    func(&d);
00F610AF  call        func (0F61000h)  
    func(&d);
00F610B4  call        func (0F61000h)  

ซึ่งแสดงว่าคอมไพเลอร์ จะละเว้นพารามิเตอร์ อย่างแน่นอนหากไม่ได้ใช้ อย่างไรก็ตาม หากฉันไม่ใส่เครื่องหมายสองบรรทัดตรงนั้นเพื่อรับที่อยู่ของฟังก์ชัน จากนั้นสิ่งต่าง ๆ ก็เปลี่ยนไป มันจะสร้างสิ่งนี้แทน:-

00C71099  lea         ecx,[esp]  
00C7109C  call        func (0C71000h)  
    func(&d);
00C710A1  lea         ecx,[esp]  
00C710A4  call        func (0C71000h)  
    func(&d);
00C710A9  lea         ecx,[esp]  
00C710AC  call        func (0C71000h)  
    func(&d);
00C710B1  lea         ecx,[esp]  
00C710B4  call        func (0C71000h) 

มันจะส่งตัวชี้ไปที่ไหน

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

อย่างไรก็ตาม เพื่อตอบคำถาม ไม่มีคอมไพเลอร์จะไม่ส่งพารามิเตอร์ที่ไม่ได้ใช้ในรีจิสเตอร์เสมอไป แต่ฉันจะไม่เขียนโค้ดใด ๆ ที่ขึ้นอยู่กับพฤติกรรมเฉพาะใด ๆ ที่นี่เป็นการเปลี่ยนโค้ดที่ไม่เกี่ยวข้องที่อื่น (รับที่อยู่ของฟังก์ชัน) เปลี่ยนไป พฤติกรรมนั้นและไม่มีอะไรรับประกันด้วยมาตรฐานใด ๆ ที่ฉันเห็น

person jcoder    schedule 12.01.2013
comment
มันสมเหตุสมผลแล้วที่การรับที่อยู่ของฟังก์ชันไม่อนุญาตให้พารามิเตอร์ที่ไม่ได้ใช้ได้รับการปรับให้เหมาะสม เนื่องจากตัวชี้ฟังก์ชันถูกพิมพ์ไปที่ลายเซ็นของฟังก์ชัน (แม้ว่าคุณจะส่งมันให้เป็นโมฆะ*) และคอมไพเลอร์โดยทั่วไปไม่สามารถทำได้ แน่นอนว่าถ้าคุณใช้มันอีกครั้งด้วยเวทมนตร์แปลกๆ +1 สำหรับการชี้ให้เห็นปัญหานี้ - person Andreas Grapentin; 12.01.2013
comment
อย่างแท้จริง. ฉันสงสัยว่าด้วยการสร้างโค้ดเวลาลิงก์ คอมไพเลอร์อาจสามารถใช้รูปแบบการเรียกแบบกำหนดเองได้หรือไม่ เนื่องจากสามารถเห็นโค้ดทั้งหมดได้ แต่เห็นได้ชัดว่าไม่ อย่างน้อยในกรณีของการทดสอบของฉัน - person jcoder; 12.01.2013
comment
ข้อสรุปหลักที่ฉันได้จากการทดสอบคือไม่ต้องพึ่งพาสิ่งนี้ในทางใดทางหนึ่ง อาจส่งผ่านพารามิเตอร์ในรีจิสเตอร์หรือไม่ก็ได้ - person jcoder; 12.01.2013
comment
การทดสอบของคุณแสดงให้เห็นว่าผู้โทรไม่ได้เติมข้อมูลในการลงทะเบียน แต่ไม่ได้แสดงว่าผู้โทรได้จัดสรรไว้หรือไม่ (เช่น อาร์กิวเมนต์ที่ตามมามีแนวโน้มที่จะหกลงบนสแต็กน้อยกว่าหรือไม่) - person JasonD; 12.01.2013
comment
ขอบคุณมาก. ฉันคิดว่าโดยทั่วไปคอมไพลเลอร์จะละเว้นจากการเปลี่ยนรูปแบบการโทรเมื่อมีการใช้ที่อยู่ของฟังก์ชันเนื่องจากตัวชี้สามารถข้ามไปยังฟังก์ชันต่างๆ ได้ - person cleong; 12.01.2013

ก่อนอื่น คอมไพลเลอร์ควรเตือนคุณเกี่ยวกับอาร์กิวเมนต์ของฟังก์ชันที่ไม่ได้ใช้ หากคุณใช้แฟล็กคอมไพเลอร์ที่เหมาะสม (เช่น -Wall) ฉันขอแนะนำให้ทิ้งอาร์กิวเมนต์ที่คุณไม่ได้ใช้ออกจากรายการอาร์กิวเมนต์ แม้ว่าฉันจะ เดาว่าพวกเขาจะได้รับการปรับให้เหมาะสม สิ่งที่คุณสามารถทำได้เพื่อให้แน่ใจว่าคอมไพล์โค้ดของคุณสองครั้ง ครั้งแรกกับอาร์กิวเมนต์และอีกครั้งไม่มี และทำ diff ระหว่างไบนารี่เพื่อดูว่าตรงกันหรือไม่ ฉันคิดว่ามันควรขึ้นอยู่กับคอมไพเลอร์ที่คุณใช้และแฟล็กการปรับให้เหมาะสม

ไชโย

แอนดี้

person Andreas Grapentin    schedule 12.01.2013
comment
ตกลงกันว่าคอมไพเลอร์จะปรับให้เหมาะสม แต่การตรวจสอบโดยใช้ diff - จะไม่สามารถตรวจสอบความแตกต่างได้ (เนื่องจากการดำเนินการขึ้นอยู่กับสิ่งอื่น ๆ มากมายที่อาจแตกต่างกันไปในแต่ละกระบวนการดำเนินการ ยิ่งไปกว่านั้น การเริ่มต้นตัวแปรจะใช้เวลามากขนาดนั้น - person exexzian; 12.01.2013
comment
@sansix ถ้าไบนารีเท่ากัน ทำไมพฤติกรรมจึงแตกต่างกัน? - person Andreas Grapentin; 12.01.2013
comment
ยังไงก็ตาม - diff b/w binaraies ของอะไร? (อาจจะกำลังคิดอย่างอื่นอยู่) - person exexzian; 12.01.2013
comment
@sansix ขออภัย ฉันไม่เข้าใจคำถามของคุณ - person Andreas Grapentin; 12.01.2013
comment
คำสั่งนี้ของคุณ do a diff between the binaries - ฉันกำลังถามไบนารี่ diff b/w ของอะไร? เวลาดำเนินการหรือ ?? - person exexzian; 12.01.2013
comment
@sansix diff เป็นเครื่องมือยูนิกซ์ในการเปรียบเทียบไฟล์ ฉันแนะนำให้เปรียบเทียบโปรแกรมที่คอมไพล์แล้วเพื่อดูว่าโค้ดที่สร้างขึ้น (ไฟล์ไบนารี 1) พร้อมอาร์กิวเมนต์ของฟังก์ชันที่ไม่ได้ใช้ตรงกับโค้ดที่สร้าง (ไฟล์ไบนารี 2) โดยไม่มีอาร์กิวเมนต์ที่ไม่ได้ใช้หรือไม่ นั่นควรเป็นวิธีที่เชื่อถือได้ในการบอกได้ว่าโฆษณาเหล่านั้นได้รับการปรับให้เหมาะสมหรือไม่ - person Andreas Grapentin; 12.01.2013
comment
โอ้ เข้าใจแล้ว นั่นจะเป็นแนวทางที่ดีแน่นอน +1 - person exexzian; 12.01.2013
comment
ไม่มีการรับประกันว่าความแตกต่างใดๆ ที่พบในไบนารีนั้นเกิดจากการละเว้นอาร์กิวเมนต์ ดังนั้นฉันไม่คิดว่ามันน่าเชื่อถือเลย - person JasonD; 12.01.2013
comment
@ JasonD ฉันยอมรับว่าความแตกต่างจะไม่บอกคุณมากนัก แต่ฉันคาดหวังว่าจะได้เห็นความเท่าเทียมกันและนั่นจะเป็นผลลัพธ์ที่สรุปได้ค่อนข้างดี :) - person Andreas Grapentin; 13.01.2013

คุณสามารถละเว้นอาร์กิวเมนต์ในนิยามฟังก์ชันได้ สิ่งนี้จะให้คำแนะนำแก่คอมไพเลอร์ว่าไม่ได้ใช้อาร์กิวเมนต์ Perticular มันจะใช้ประโยชน์จากมันและปรับโค้ดให้เหมาะสม

เป็นโมฆะ func (สาธิตโครงสร้าง *) { ... }

person sameer chaudhari    schedule 10.02.2017