2013-04-09 21 views
12

Tôi muốn làm rõ một số điểm về lưu trữ các biến đăng ký: Có cách nào để đảm bảo rằng nếu chúng ta khai báo biến đăng ký trong mã của chúng ta, nó sẽ CHỈ được lưu trữ trong sổ đăng ký?Làm thế nào để lưu trữ biến C++ trong sổ đăng ký

#include<iostream> 
using namespace std; 
int main() 
{ 
register int i=10;// how can we ensure this will store in register only. 
i++; 
cout<<i<<endl; 
return 0; 
} 
+10

C và C++ không đảm bảo rằng phần cứng mà chương trình đang chạy thậm chí có "đăng ký". Nó chỉ là một gợi ý cho trình biên dịch. –

+3

Tại sao bạn quan tâm? – delnan

+4

@StephenCanon Không chỉ đơn thuần là một gợi ý trong C, tuyên bố một biến 'đăng ký' cấm lấy địa chỉ của nó ở đó. (Nó không phải là nhiều hơn có thể là một gợi ý như xa như việc đặt các biến thực sự trong một đăng ký là có liên quan.) –

Trả lời

28

Bạn không thể. Nó chỉ là một gợi ý cho trình biên dịch cho thấy rằng biến được sử dụng nhiều. Đây là từ ngữ C99:

Tuyên bố xác định cho đối tượng có loại lưu trữ speci 01 er register gợi ý rằng truy cập vào đối tượng càng nhanh càng tốt. Mức độ mà các đề xuất như vậy có hiệu quả là việc triển khai thực hiện.

Và đây là C++ 11 từ ngữ:

Một specifier register là một gợi ý để thực hiện điều đó biến để tuyên bố sẽ được sử dụng rất nhiều. [Lưu ý: Các gợi ý có thể được bỏ qua và trong hầu hết các triển khai nó sẽ bị bỏ qua nếu địa chỉ của biến được thực hiện. Việc sử dụng này không được chấp nhận (xem D.2). lưu ý end]

Trong thực tế, register lưu trữ lớp specifier bị phản đối trong C++ 11 (Phụ lục Q.2):

Việc sử dụng các từ khóa register như một kho lưu -specifier (7.1.1) không được chấp nhận.

Lưu ý rằng bạn không thể lấy địa chỉ của biến số register trong C vì sổ đăng ký không có địa chỉ. Hạn chế này được loại bỏ trong C++ và lấy địa chỉ được đảm bảo khá nhiều để đảm bảo biến sẽ không kết thúc trong sổ đăng ký.

Nhiều trình biên dịch hiện đại chỉ đơn giản bỏ qua từ khóa register trong C++ (trừ khi nó được sử dụng theo cách không hợp lệ, tất nhiên). Chúng đơn giản hơn nhiều khi tối ưu hóa hơn so với khi từ khóa register hữu ích. Tôi mong đợi các trình biên dịch cho các nền tảng mục tiêu thích hợp để xử lý nó nghiêm túc hơn.

+1

Nó luôn làm tôi ngạc nhiên khi thấy mã được đánh dấu ** mọi biến ** cục bộ bằng 'đăng ký'. –

+3

@PeteBecker Ai cần RAM? Tôi là tất cả người đăng ký! –

+0

đối số của bạn chỉ là C++. C áp đặt các hạn chế đối với các biến đăng ký. –

3

Đó chỉ là gợi ý cho trình biên dịch; bạn không thể buộc nó để đặt biến vào sổ đăng ký. Trong bất kỳ trường hợp nào, trình biên dịch có thể có kiến ​​thức tốt hơn về kiến ​​trúc đích so với trình lập trình ứng dụng, và do đó được đặt tốt hơn để viết mã làm cho các quyết định phân bổ đăng ký. Nói cách khác, bạn không thể đạt được bất cứ điều gì bằng cách sử dụng register.

+0

đối số của bạn chỉ là C++. C áp đặt các hạn chế đối với các biến đăng ký. –

3

Nói chung là không thể. Cụ thể, người ta có thể thực hiện các biện pháp nhất định để tăng xác suất:

Sử dụng mức tối ưu thích hợp, ví dụ: -O2

Giữ số lượng các biến nhỏ

register int a,b,c,d,e,f,g,h,i, ... z; // can also produce an error 
// results in _spilling_ a register to stack 
// as the CPU runs out of physical registers 

Đừng lấy địa chỉ của biến đăng ký.

register int a; 
int *b = &a; /* this would be an error in most compilers, but 
       especially in the embedded world the compilers 
       release the restrictions */ 

Trong một số trình biên dịch, bạn có thể đề nghị

register int a asm ("eax"); // to put a variable to a specific register 
+0

đối số của bạn chỉ là C++. C áp đặt các hạn chế đối với biến 'register'. Ngoài ra ví dụ của bạn từ gcc về 'asm' là gây hiểu nhầm. Đối với gcc, đây không phải là "gợi ý". Nếu bạn chỉ định một thanh ghi, thanh ghi đó sẽ tồn tại và * sẽ * được sử dụng. –

1

"Đăng ký" từ khóa là một tàn dư của thời gian khi trình biên dịch phải phù hợp trên máy với 2MB RAM (chia sẻ giữa 18 thiết bị đầu cuối với một người dùng đã đăng nhập trên mỗi người dùng). Hoặc PC/Home máy tính với 128-256KB RAM. Tại thời điểm đó, trình biên dịch không thể thực sự chạy qua một hàm lớn để tìm ra sổ đăng ký nào sử dụng cho biến nào, để sử dụng thanh ghi hiệu quả nhất. Vì vậy, nếu các lập trình viên đã đưa ra một "gợi ý" với register, trình biên dịch sẽ đặt trong một thanh ghi (nếu có thể).

Trình biên dịch hiện đại không phù hợp với nhiều lần trong 2MB RAM, nhưng chúng thông minh hơn khi chỉ định biến cho thanh ghi. Trong ví dụ được đưa ra, tôi tìm thấy nó rất cởi mở mà trình biên dịch sẽ không đặt nó trong sổ đăng ký. Rõ ràng, các thanh ghi bị giới hạn về số lượng, và đưa ra một đoạn mã đầy đủ phức tạp, một số biến sẽ không vừa trong sổ đăng ký. Nhưng đối với một ví dụ đơn giản như vậy, một trình biên dịch hiện đại sẽ làm cho i một thanh ghi, và nó có thể sẽ không chạm vào bộ nhớ cho đến đâu đó bên trong ostream& ostream::operator<<(ostream& os, int x).

+0

haha, 18 thiết bị đầu cuối trên 2MB. xuống bãi cỏ của tôi :-) [CP-67 đã hỗ trợ 60 người dùng] (http://www.leeandmelindavarian.com/Melinda/25paper.pdf) [trên một nửa số đó] (http://bitsavers.trailing-edge.com /pdf/ibm/360/funcChar/GA27-2719-2_360-67_funcChar.pdf). – jthill

+0

Vâng, trường học của tôi chia sẻ một 2MB PDP-11 chạy RSTS-E, và nó có 8 thiết bị đầu cuối và một máy in tại trường của tôi, 8 + 1 ở trường tiếp theo, và sau đó trường chính có hai phòng với 16 thiết bị đầu cuối trong mỗi phòng (cộng với một vài thiết bị đầu cuối ngẫu nhiên nằm rải rác ở một vài nơi khác). Và có một trình biên dịch C cho điều đó, nhưng hầu hết chúng ta đã sử dụng ngôn ngữ hiện đại vào thời điểm đó, Pascal. –

5

Từ khóa register có ý nghĩa khác nhau trong C và C++. Trong C++ nó là trong thực tế dư thừa và dường như thậm chí không được chấp nhận ngày nay.

Trong C, nó khác. Trước tiên, không lấy tên của từ khóa theo nghĩa đen, nó không phải lúc nào cũng liên quan đến "đăng ký phần cứng" trên một CPU hiện đại. Hạn chế được áp dụng cho các biến số register là bạn không thể lấy địa chỉ của chúng, hoạt động & không được phép. Điều này cho phép bạn đánh dấu một biến để tối ưu hóa và đảm bảo rằng trình biên dịch sẽ hét vào bạn nếu bạn cố gắng lấy địa chỉ của nó. Cụ thể, biến số register cũng là const đủ điều kiện không bao giờ có thể bí danh, do đó, nó là một ứng cử viên tốt cho tối ưu hóa.

Sử dụng register như trong C có hệ thống buộc bạn phải suy nghĩ về mọi địa điểm nơi bạn lấy địa chỉ của một biến. Đây có lẽ là không có gì bạn muốn làm trong C++, mà phụ thuộc rất nhiều vào tài liệu tham khảo cho các đối tượng và những thứ như thế. Đây có thể là lý do tại sao C++ không sao chép thuộc tính này của register biến từ C.

+0

Tôi nghĩ rằng bạn có nghĩa là "nghĩa đen" (hoặc "nguyên văn") thay vì "tiết" trong câu đầu tiên của đoạn hai. – Jeff

0

Cách duy nhất để đảm bảo rằng bạn đang sử dụng đăng ký, là sử dụng lắp ráp nội tuyến. Nhưng, ngay cả khi bạn làm điều này, bạn không được đảm bảo rằng trình biên dịch sẽ không lưu trữ giá trị bên ngoài của khối lắp ráp nội tuyến của bạn. Và, tất nhiên, hệ điều hành của bạn có thể quyết định làm gián đoạn chương trình của bạn tại bất kỳ thời điểm nào, lưu trữ tất cả các thanh ghi của bạn vào bộ nhớ, để cung cấp cho CPU cho một quá trình khác. Vì vậy, trừ khi bạn viết mã lắp ráp trong hạt nhân với tất cả các ngắt bị vô hiệu hóa, hoàn toàn không có cách nào để đảm bảo rằng biến của bạn sẽ không bao giờ đánh vào bộ nhớ.

Tất nhiên, điều đó chỉ liên quan nếu bạn lo lắng về sự an toàn. Từ góc độ hiệu suất, biên dịch với -O3 thường là đủ, trình biên dịch thường thực hiện khá tốt công việc xác định biến nào được giữ trong sổ đăng ký. Dù sao, việc lưu trữ các biến trong thanh ghi chỉ là một khía cạnh nhỏ của việc điều chỉnh hiệu suất, khía cạnh quan trọng hơn nhiều là đảm bảo rằng không có công việc thừa hoặc đắt tiền nào được thực hiện trong vòng lặp bên trong.

0

Tại đây bạn có thể sử dụng volatile register int i = 10 trong C++ để đảm bảo i được lưu trữ trong đăng ký. volatile từ khóa sẽ không cho phép trình biên dịch tối ưu hóa biến số i.

1

Trình biên dịch CPP nói chung (g ++) thực hiện một số tối ưu hóa cho mã. Vì vậy, khi bạn khai báo một biến đăng ký, không cần thiết trình biên dịch sẽ lưu trữ giá trị đó trực tiếp trong thanh ghi. (ví dụ) mã 'đăng ký int x' có thể không dẫn đến trình biên dịch lưu trữ int đó trực tiếp trong thanh ghi. Nhưng nếu chúng ta có thể buộc trình biên dịch làm như vậy, chúng ta có thể thành công.

Ví dụ: nếu chúng tôi sử dụng đoạn mã sau, thì chúng tôi có thể buộc trình biên dịch thực hiện những gì chúng tôi mong muốn. Việc biên dịch đoạn mã sau đây có thể bị lỗi, điều này cho biết rằng int thực sự được lưu trữ trực tiếp trong thanh ghi.

int main() { 
    volatile register int x asm ("eax"); 
    int y = *(&x); 
    return 0; 
} 

Đối với tôi, trình biên dịch g ++ đang ném lỗi sau trong trường hợp này.

[[email protected] cpp]$ g++ register_vars.cpp 
register_vars.cpp: In function ‘int main()’: 
register_vars.cpp:3: error: address of explicit register variable ‘x’ requested 

Dòng 'bay hơi đăng ký int x asm ('eax')' được hướng dẫn trình biên dịch rằng, lưu trữ các số nguyên x trong 'eax' đăng ký và khi làm như vậy không làm bất cứ việc tối ưu. Điều này sẽ đảm bảo rằng giá trị được lưu trữ trong sổ đăng ký trực tiếp. Đó là lý do tại sao truy cập vào địa chỉ của biến là ném một lỗi.

Hoặc, trình biên dịch C (gcc), có thể bị lỗi với chính đoạn mã sau.

int main() { 
    register int a=10; 
    int c = *(&a); 
    return 0; 
} 

Đối với tôi, trình biên dịch gcc đang ném lỗi sau trong trường hợp này.

[[email protected] cpp]$ gcc register.c 
register.c: In function ‘main’: 
register.c:5: error: address of register variable ‘a’ requested 
+0

Cú pháp 'asm (" eax ")' này chính xác là những gì tôi đang tìm kiếm. cảm ơn vì đã trả lời câu hỏi – portforwardpodcast

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