2010-07-30 24 views
9

Tôi muốn biết rằng khối tĩnh trong c hoặc C++ là gì? Tôi biết những gì là tĩnh nhưng sự khác biệt giữa tĩnh và tĩnh khối là gì?Khối tĩnh trong c hoặc C++ là gì?

+13

Không có điều gì như vậy, bằng cả hai ngôn ngữ. –

+1

kiểm tra tiêu đề của bạn cho một số #define block .... có thể ai đó đã xác định "chặn" ... – santa

+0

@Neil - Tôi đã khám phá khái niệm "tĩnh" thông qua công cụ tìm kiếm của Google và khi tôi nhập "khối tĩnh" tại google , tôi tìm thấy một tùy chọn nói rằng "khối tĩnh trong c" – Abhineet

Trả lời

28

Một giải pháp thay thế khác là bạn có thể đang tìm kiếm sự tương tự của khối tĩnh trong Java. Một khối mã được chạy khi ứng dụng được tải. Không có điều gì trong C++ nhưng nó có thể được giả mạo bằng cách sử dụng hàm tạo của đối tượng tĩnh .

foo.cpp: 

struct StaticBlock { 
    StaticBlock(){ 
     cout << "hello" << endl; 
    } 
} 


static StaticBlock staticBlock; 

void main(int, char * args[]){ 

} 

BAO GIỜ. Tôi đã bị cắn bởi điều này trước đây vì nó là một trường hợp cạnh tinh tế của tiêu chuẩn C++ . Nếu đối tượng tĩnh không thể truy cập được bằng bất kỳ mã nào được gọi bằng chính, thì hàm tạo của đối tượng tĩnh có thể hoặc không được gọi là .

Tôi thấy rằng với gcc hello sẽ nhận được kết quả đầu ra và với studio trực quan, nó sẽ không.

+3

+1: Ngoài ra, thứ tự khởi tạo là không xác định, mà cũng có thể cung cấp cho tất cả các loại nhức đầu. Tôi cũng muốn thấy một khung khởi tạo tĩnh đáng tin cậy. –

+0

+1 để đề cập đến trường hợp không thể truy cập có thể xảy ra. Bạn có chắc chắn nó không được gọi và không chỉ được gỡ bỏ tại thời gian biên dịch hoàn toàn? Tôi sẽ nghi ngờ ngay cả gcc sẽ làm điều này với cờ tối ưu hóa đủ. – EntangledLoops

+1

@EntangledLoops: Không, bạn có thể yên tâm rằng nó [không bị xóa] (http://coliru.stacked-crooked.com/a/6af8f97e6f5f7610). bradgonesurfing: Tại sao bận tâm sử dụng một lớp học? Không phải là nó đủ để chỉ [tĩnh-khởi tạo một int với với một chức năng] (http://stackoverflow.com/a/34321324/1593077)? – einpoklum

0

Trong C++ có khái niệm về một không gian tên ẩn danh.

foo.cpp: 

namespace { 
    int x; 
    int y; 
} 

để có được những tác dụng tương tự trong C

foo.cpp: 

static int x; 
static int y; 

Trong thuật ngữ đơn giản trình biên dịch không xuất biểu tượng từ đơn vị dịch khi họ hoặc là tuyên bố tĩnh hoặc trong một không gian tên vô danh.

+0

"Biểu tượng xuất" có ý nghĩa gì? Tiêu chuẩn C++ không định nghĩa thuật ngữ này. Tuy nhiên, nó nói về "liên kết" và liên quan đến tuyên bố của bạn là sai như xa như tôi có thể nói. Hai ví dụ này không có tác dụng tương tự. 'x' và' y' từ không gian tên ẩn danh có liên kết bên ngoài trong khi hai tên kia có liên kết nội bộ. Nhưng tôi hiểu ý bạn là gì. Bạn có nghĩa là các đơn vị dịch thuật khác không thể tham chiếu đến các biến này theo tên. – sellibitze

+0

Các mục trong không gian tên ẩn danh chỉ có * liên kết nội bộ *. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/unnamed_namespaces.htm tốt, do đó, IBM nói. Có ai có một con trỏ đến tiêu chuẩn C + + về điều này? – bradgonesurfing

+0

Ok. Tôi đã theo dõi một bản sao của tiêu chuẩn và nó nói như sau. "Mặc dù các thực thể trong một không gian tên không có tên có thể có liên kết bên ngoài, chúng có hiệu quả bằng tên duy nhất cho đơn vị dịch của chúng" Tôi nghi ngờ trong thực tế nó sẽ phụ thuộc vào trình biên dịch nhưng hiệu quả là như nhau. – bradgonesurfing

5

Không có khái niệm nào với tên "khối tĩnh" trong C/C++. Java có nó tuy nhiên, một "khối tĩnh" là một khối mã khởi tạo cho một lớp chạy chính xác một lần, trước khi thể hiện đầu tiên của một lớp được tạo ra. Các khái niệm cơ bản 'thứ mà chạy đúng một lần' có thể mô phỏng trong C/C++ với một biến tĩnh, ví dụ:

int some_function(int a, int b) 
{ 
static bool once=true; 
if (once) 
{ 
    // this code path runs only once in the program's lifetime 
    once=false; 
} 
... 
} 

Đây không phải là thread-safe tuy nhiên. Nhận được quyền làm việc này trong sự hiện diện của nhiều chủ đề có thể đôi khi khó khăn và phức tạp.

15

Tôi đã tìm thấy this câu trả lời trên Dự án mã. Nó liên quan đến việc có thêm một biến tĩnh, nhưng tôi tin rằng nó đáng tin cậy hơn câu trả lời của bradgonesurfing. Về cơ bản, nó là thế này:

class Foo 
{ 
public: 
    static int __st_init; 
private: 
    static int static_init(){ 
     /* do whatever is needed at static init time */ 
     return 42; 
    } 
}; 
int Foo::__st_init = Foo::static_init(); 

Nó cũng có nghĩa rằng, giống như các khối tĩnh Java, bạn không cần phải bao giờ thực sự có một thể hiện của class Foo, đó là hữu ích khi lớp có thể mất rất nhiều dữ liệu, và bạn chỉ cần tự động gọi một cái gì đó trước khi nó tải, không khởi tạo thêm một thể hiện của nó. Bạn có thể kiểm tra khối mã chính xác đó. Tôi chỉ biên dịch nó (với một đầu ra nhỏ từ static_init(), và có chính() in Foo :: __ st_init, chỉ để chắc chắn), và nó đã làm việc tốt.

$g++ -v 

Using built-in specs. 
COLLECT_GCC=g++ 
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper 
Target: x86_64-linux-gnu 
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu 
Thread model: posix 
gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) 

EDIT:

Xin lỗi rằng đây là quá muộn, nhưng tôi đã thử nghiệm những gì bradgonesurfing đề cập:

Nếu bạn kiểm tra nó tôi truy cập vào biến trong chính "chỉ để chắc chắc chắn " bạn đang đảm bảo biến có thể truy cập được và do đó biến sẽ được khởi tạo và do đó static_init sẽ được gọi. Bạn có chắc chắn nó thực hiện nếu bạn không in Foo :: __ st_init

tôi đã sử dụng main.cpp bên sau:

#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    static int __st_init; 
private: 
    static int static_init(){ 
     /* do whatever is needed at static init time */ 
     cout << "Hello, World!"; 
     return 42; 
    } 
}; 
int Foo::__st_init = Foo::static_init(); 

int main(int argc, char** argv) 
{ 
     return 0; 
} 

tôi biên soạn với g++ ./main.cpp -o main và chạy nó và nhận được một thân thiện "Hello, Thế giới! " tin nhắn trên bảng điều khiển của tôi. Chỉ cần để được triệt để, tôi cũng biên dịch cùng một phiên bản nhưng không có in ấn và biên soạn với g++ ./main.cpp -g -o main. Sau đó tôi chạy thực thi với gdb và có kết quả sau:

(gdb) break Foo::static_init 
Breakpoint 1 at 0x400740: file ./main.cpp, line 12. 
(gdb) start 
Temporary breakpoint 2 at 0x4006d8: file ./main.cpp, line 19. 
Starting program: /home/caleb/Development/test/main-c++ 

Breakpoint 1, Foo::static_init() at ./main.cpp:12 
12    return 42; 
(gdb) 

Dưới đây là một nhiều hơn hiện tại phiên bản đầu ra cho g ++: g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

+2

Nếu bạn kiểm tra nó, truy cập biến trong chính "chỉ để đảm bảo" bạn đảm bảo biến có thể truy cập được và do đó biến sẽ được khởi tạo và do đó static_init sẽ được gọi. Bạn có chắc nó thực hiện nếu bạn không ** in Foo :: __ st_init – bradgonesurfing

+0

Đó là một điểm tuyệt vời, bradgonesurfing. Tôi đã cập nhật câu trả lời của mình với các bài kiểm tra đầy đủ và có vẻ như nó vẫn hoạt động. Xin lỗi vì đã trễ hai năm, nếu bạn đã từng đọc ... Tôi không biết tại sao tôi không bao giờ trả lời. – Caleb1994

+1

Cảm ơn một cách tiếp cận hoạt động trong một số trường hợp, nhưng thật không may, điều này không hoạt động nếu bạn gọi phương thức tĩnh bên trong, ví dụ, một thư viện tĩnh riêng biệt ... Ngay cả khi bạn đưa tiêu đề Foo vào main.cpp của mình. –

1

Trong khi trên thực tế, C++ không có khối tĩnh như một phần của ngôn ngữ, bạn thể thực hiện khối tĩnh mà không có em (như là một người sử dụng) phải sử dụng bất kỳ lớp học hoặc không gian tên, và có thể viết:

#include "static_block.h" 

static_block { 
    int x = 1; 
    int y = 2; 
    int z = x+y; 
    std::cout << z << " = " << x " << " + " << y << "\n"; 
} 

hoặc bất cứ điều gì khác mà bạn muốn. Tuy nhiên, bạn không thể có những lớp đó trong phạm vi tệp. Xem mô tả chi tiết về những điều này trong số answer của tôi cho câu hỏi có liên quan và mã cho static_block.hhere.

Lưu ý: Điều này không yêu cầu C++ 11 và sẽ hoạt động tốt với trình biên dịch cũ.

+0

Đó là một giải pháp thú vị, nhưng điều đáng nói đến là có nhiều hơn nó sau đó là khối mã bạn đăng. Có một vài macro được định nghĩa và nó sử dụng lambda C++ 11. Tôi đồng ý rằng giải pháp của bạn cung cấp một cách tiếp cận hợp lý hơn (cũng thanh lịch). Nó sử dụng các tính năng của C++ 11 mà tôi không quen thuộc với thời gian. Câu trả lời của tôi đã được viết cách đây 4 năm khi tiêu chuẩn C++ 11 là khá mới và không nhất thiết phải là luồng chính. – Caleb1994

+0

@ Caleb1994: Trên thực tế, cơ chế này không liên quan gì đến C++ 11, đó là C++ 98 và thậm chí có thể sớm hơn. Không sử dụng các danh sách khởi tạo, các lớp, không có gì lạ mắt - chỉ một số nội trang dựng sẵn tiền xử lý cho một định danh duy nhất, và thực tế là C++ có khởi tạo tĩnh. Dù sao, tôi đã bao gồm một câu lệnh '# include' và một liên kết đến mã. – einpoklum

+0

Rất tiếc, tôi đã đọc sai câu trả lời. Có, không có sự ưa thích-ness đang diễn ra trên giải pháp của bạn. Bạn đúng. Mặc dù, giải pháp lambdas C++ 11 ở trên của bạn trông khá đẹp. Nó có thể được sử dụng trong phạm vi chức năng (mặc dù cá nhân tôi chưa thử nghiệm nó). Giải pháp của bạn là thủ tục và thậm chí sẽ làm việc trong C89 tôi nghĩ, haha. – Caleb1994