2010-10-20 30 views
25

Tôi đã được hỏi một câu hỏi phỏng vấn để thay đổi điểm vào của chương trình C hoặc C++ từ main() thành bất kỳ chức năng nào khác. Làm thế nào là nó có thể?trong C++ chức năng chính là điểm vào chương trình làm thế nào tôi có thể thay đổi nó sang một chức năng khác?

+9

Bạn không. Nó phải là 'main', hoặc một số điểm vào được xác định. Không có cách tiêu chuẩn. – GManNickG

+8

Phụ thuộc vào trình biên dịch/trình liên kết của bạn. – casablanca

+1

Điểm vào của chương trình là nơi nó bắt đầu thực hiện ở cấp mã máy. Đó là hiếm khi nếu bao giờ 'chính'; thay vào đó, hàm điểm vào thực hiện một vài nhiệm vụ khởi tạo và sau đó, đối với một chương trình C hoặc C++, hãy gọi 'main'. Vì vậy, câu hỏi không có ý nghĩa. Bạn có chắc đó là câu hỏi chính xác không? –

Trả lời

40

Trong tiêu chuẩn C (và, tôi tin rằng, C++), bạn không thể, ít nhất là không cho một môi trường lưu trữ (nhưng xem bên dưới). Tiêu chuẩn quy định rằng điểm bắt đầu cho mã C là main. Tiêu chuẩn (c99) không để lại nhiều phạm vi cho đối số:

5.1.2.2.1 Khởi động chương trình: (1) Chức năng được gọi lúc khởi động chương trình được đặt tên chính.

Vậy đó. Sau đó nó quế một chút về các thông số và giá trị trả về nhưng thực sự không có thay đổi gì về việc thay đổi tên.

Đó là dành cho môi trường được lưu trữ. Tiêu chuẩn này cũng cho phép một môi trường tự do (tức là, không có hệ điều hành nào, cho những thứ như hệ thống nhúng). Đối với môi trường tự do:

Trong môi trường tự do (trong đó thực thi chương trình C có thể diễn ra mà không có bất kỳ lợi ích nào của hệ điều hành), tên và loại chức năng được gọi là khởi động chương trình. Bất kỳ cơ sở thư viện nào có sẵn cho một chương trình tự do, trừ tập hợp tối thiểu theo yêu cầu của khoản 4, được xác định thực hiện.

Bạn có thể sử dụng "thủ đoạn gian trá" trong C triển khai để bạn có thể làm cho nó trông giống như main không phải là điểm mấu chốt. Điều này thực tế là những gì mà những người tuân thủ Windows sớm đã làm để đánh dấu WinMain là điểm bắt đầu.


cách đầu tiên: một mối liên kết có thể bao gồm một số mã khởi động trước chính trong một tập tin như start.o và nó là đoạn mã này mà chạy để thiết lập môi trường C sau đó gọi main. Không có gì để ngăn bạn thay thế bằng cái gì đó gọi số bob.


Cách thứ hai: một số trình liên kết cung cấp tùy chọn đó với công tắc dòng lệnh để bạn có thể thay đổi mà không cần biên dịch lại mã khởi động.


Cách thứ ba: bạn có thể liên kết với đoạn mã này:

int main (int c, char *v[]) { return bob (c, v); } 

và sau đó điểm vào của bạn cho đang của bạn là dường như bob hơn main.


Tuy nhiên, tất cả điều này, trong khi quan tâm có thể học tập, không làm thay đổi thực tế là tôi không thể nghĩ ra một tình huống đơn độc duy nhất trong nhiều thập kỷ của tôi về cắt mã, nơi đây sẽ là một trong hai cần thiết hoặc mong muốn.

Tôi sẽ hỏi người phỏng vấn: tại sao bạn muốn để thực hiện việc này?

+0

như được gắn thẻ nó là một câu hỏi trong cuộc phỏng vấn của tôi bây giờ không phải là nó có thể hay không nếu có thể thì làm thế nào thanx cho ans. – Badr

+6

+1 để tạo 'main' chỉ cần gọi một thứ khác. Đó là phương pháp đơn giản nhất và đa nền tảng để thực hiện điều này. – Seth

+0

Không phải là có thể thực hiện một số hackery được xác định thực hiện với các nhà xây dựng của các đối tượng toàn cầu? Những con quỷ bay ra khỏi mũi của bạn trên các nền tảng khác được đảm bảo, tất nhiên. – slartibartfast

6

Nếu bạn đang ở trên VS2010, this có thể cung cấp cho bạn một số ý tưởng

Vì nó là dễ hiểu, điều này là không bắt buộc của chuẩn C++ và rơi trong lĩnh vực 'hành vi cụ thể triển khai thực'.

3

Sửa đổi đối tượng crt thực sự gọi hàm main() hoặc cung cấp chức năng của riêng bạn (đừng quên tắt liên kết của bình thường).

+0

Tôi có thể làm như thế nào? –

7

Từ tài liệu tiêu chuẩn C++ 3.6.1 Chức năng chính,

Một chương trình phải có một chức năng toàn cầu gọi là chính, mà là sự bắt đầu chỉ định của chương trình. Nó được thực hiện theo quy định cho dù một chương trình trong môi trường tự do là bắt buộc để xác định một chức năng chính.

Vì vậy, nó không phụ thuộc trên trình biên dịch của bạn/mối liên kết ...

+0

Điều đó thật thú vị. Không có dấu hiệu nào trong cpp0x rằng câu đầu tiên chỉ áp dụng để lưu trữ, và 'sẽ' thường là một từ tiêu chuẩn có nghĩa là nó _must_ là như vậy. Vì vậy, nó xuất hiện rằng 'chính' phải tồn tại ngay cả đối với freestanding. Có thể một người nào đó với nhiều C++ - Standard-fu hơn tôi con số đó ra? Bạn có thể _have_ một 'main' mà không cần phải xác định nó? – paxdiablo

+0

Thực ra dường như cũng giống như trường hợp của C. Tôi đang xem phần được lưu trữ. Phần freestanding là một chút lỏng lẻo với các yêu cầu. +1. – paxdiablo

+0

@paxdiablo: Tôi nghĩ ý định là câu thứ hai đủ điều kiện cho câu đầu tiên, để nó có nghĩa là "Một chương trình [trong môi trường được lưu trữ] sẽ chứa ..." Tôi nghĩ "sẽ chứa" có nghĩa là "sẽ chứa [một định nghĩa của]; " Tôi không biết từ "chứa" có thể được hiểu như thế nào. –

1

Trên cửa sổ có một (chứ không phải không chính thống) cách để thay đổi điểm nhập cảnh của một chương trình: TLS. Xem phần này để được giải thích thêm: http://isc.sans.edu/diary.html?storyid=6655

1

Đối với hệ thống dựa trên Solaris Tôi đã tìm thấy this. Bạn có thể sử dụng phần .init cho mỗi nền tảng Tôi đoán:

pragma init (function [, function]...) 

Nguồn:

pragma Điều này làm cho mỗi chức năng được liệt kê được gọi là trong quá trình khởi (trước chính) hoặc trong quá trình chia sẻ mô-đun tải, bằng cách thêm một cuộc gọi đến phần .init.

5

Các điểm nhập cảnh thực sự là _start chức năng (thực hiện trong crt1.o).

Chức năng _start chuẩn bị các đối số dòng lệnh và sau đó gọi main(int,char*[]), bạn có thể thay đổi các điểm nhập cảnh từ _start để mystart bằng cách thiết lập một tham số mối liên kết:

g++ file.o -Wl,-emystart -o runme 

Tất nhiên, đây là một sự thay thế cho điểm nhập _start để bạn không nhận được các đối số dòng lệnh:

void mystart(){ 

} 
0

Có, Chúng ta có thể thay đổi tên hàm chính thành bất kỳ tên nào khác cho ví dụ. Bắt đầu, bob, rem, v.v.

Trình biên dịch biết rằng nó phải tìm kiếm hàm main() trong toàn bộ mã?

Không có gì là tự động trong lập trình. ai đó đã thực hiện một số công việc để làm cho nó trông tự động cho chúng tôi.

do đó nó đã được xác định trong tệp khởi động mà trình biên dịch nên tìm kiếm chính().

chúng tôi có thể thay đổi tên chính thành bất kỳ điều gì khác, ví dụ: Bob và sau đó trình biên dịch sẽ chỉ tìm kiếm Bob().

1

Nó rất đơn giản:

Như bạn nên biết khi bạn sử dụng các hằng số trong c, trình biên dịch thực hiện một loại 'vĩ mô' thay đổi tên của hằng số cho giá trị tương ứng.

chỉ bao gồm một cuộc tranh luận #define vào đầu mã của bạn với tên của chức năng khởi động tiếp theo là tên main:

Ví dụ:

#define my_start-up_function (main) 
1

Với gcc, khai báo hàm với thuộc tính ((constructor)) và gcc sẽ thực thi hàm này trước bất kỳ mã nào khác bao gồm cả main.

3

Đây là tính đầu cơ cao, nhưng bạn có thể có một initializer tĩnh thay vì chính:

bao gồm

int mymain() 
{ 
    std::cout << "mymain"; 
    exit(0); 
} 

static int sRetVal = mymain(); 

int main() 
{ 
    std::cout << "never get here"; 
} 

Bạn thậm chí có thể làm cho nó 'Java như', bằng cách đặt những thứ trong một constructor :

#include <iostream> 

class MyApplication 
{ 
public: 
    MyApplication() 
    { 
     std::cout << "mymain"; 
     exit(0); 
    } 
}; 

static MyApplication sMyApplication; 

int main() 
{ 
    std::cout << "never get here"; 
} 

Hiện tại. Người phỏng vấn có thể đã nghĩ về điều này, nhưng cá nhân tôi không bao giờ sử dụng chúng. Lý do là:

  • Nó không thông thường. Mọi người sẽ không hiểu nó, nó không cần thiết để tìm điểm vào.
  • Thứ tự khởi tạo tĩnh là không xác định. Đặt trong một biến tĩnh và bạn sẽ không bao giờ ngay bây giờ nếu nó được khởi tạo.

Điều đó nói rằng, tôi đã thấy nó được sử dụng trong sản xuất thay vì init() cho người khởi tạo thư viện. Các caveat là, trên cửa sổ, (từ kinh nghiệm) statics của bạn trong một DLL có thể hoặc có thể không được khởi tạo dựa trên cách sử dụng.

0

Tôi nghĩ rằng việc xóa biểu tượng chính() không mong muốn khỏi đối tượng trước khi liên kết là dễ dàng.

Rất tiếc, tùy chọn điểm nhập cho g ++ không hoạt động đối với tôi (lỗi nhị phân trước khi nhập điểm nhập). Vì vậy, tôi dải không mong muốn entry-point từ tập tin đối tượng.

Giả sử chúng tôi có hai nguồn chứa chức năng điểm nhập.

  1. target.c chứa chính() chúng tôi không muốn.
  2. our_code.c chứa testmain() chúng tôi muốn là điểm vào.

Sau khi biên dịch (tùy chọn g ++ -c), chúng tôi có thể nhận được các tệp đối tượng sau.

  1. nhắm mục tiêu.o, có chứa chính() chúng tôi không muốn.
  2. our_code.o chứa testmain() chúng tôi muốn là điểm vào.

Vì vậy, chúng tôi có thể sử dụng objcopy để loại bỏ hàm main() không mong muốn.

objcopy --strip-biểu tượng = target.o chính

Chúng ta có thể xác định lại testmain() để main() sử dụng objcopy quá.

objcopy --redefine-sym testmain = our_code.o chính

Và sau đó chúng ta có thể liên kết cả hai trong số họ vào nhị phân.

g ++ target.o our_code.o -o our_binary.bin

này làm việc cho tôi. Bây giờ khi chúng tôi chạy our_binary.bin điểm vào là our_code.c:main() chức năng.

Các vấn đề liên quan