Global variable: static hay không static

Giả sử mình có một vài biến và hàm có thể dùng chung và mình muốn để tụi nó global mình viết như sau trong header file Common.h

int length = 100;
void printSomething();

Trong file C++ thì mình viết code cho hàm printSomething();
Trong file main.cpp mình include Common.h

#include “Common.h”
int main()
{
int data = 300 - length;
printSomething();
}

Khi mình build code thì nó báo lỗi linker vì length đã được định nghĩa rồi. Theo mình hiểu là tại vì trong Common.cpp cũng include Common.h (hiển nhiên) nên khi mình include Common.h trong main.cpp thì nó hiểu là có 2 biến length và vì trùng tên nên bị lỗi linker.
Mình có 3 cách sửa:
Cách 1: định nghĩa luôn hàm trong header để khỏi bị include header nhiều lần.
Cách 2: thêm static vào trước length.
Cách 3: nếu chỉ là variable, mình tạo một cái header riêng gọi là Variable_Common.h và lưu các biến đó ở đây.
Cách 1 mình không nói. Cách 2 và 3 khác nhau ở chổ dùng keyword static. Cho mình hỏi nên hiểu 2 trường hợp này như thế nào và nên dùng như thế nào cho hợp lí? Cho mình hỏi static có tác dụng như thế nào? Theo mình biết nó là như vầy:

  1. static trong 1 lớp: nếu là một biến trong lớp đó thì biến này sẽ được chia sẻ với các object của lớp này, nếu là method thì có thể gọi thông qua tên lớp mà không cần tạo object.
  2. static nằm strong hàm: khởi tạo một lần duy nhất khi gọi hàm, những lần gọi sau, hàm sẽ dùng biến static này.
  3. Nếu như define một biến global và thêm static trong một file nào đó, ví dụ President.h, nhưng mình không include cái President.h ở đâu hết thì có thể hiểu là cái biến đó chỉ global cho đúng President.h mà thôi. Còn lại nó private với các file khác.

Edit: mình không muốn dùng extern.

1 Like

cách 1: đừng xài biến global

chấm hết :V


cũng là cách cin/cout được khai báo

5 Likes

Cái này đâu phải là câu hỏi vì em đã có luôn câu trả lời cho em rồi mà. Tóm lại là cách nào cũng xài được và nó đều hữu dụng. Vd biến static trong class để chỉ tạo 1 biến duy nhất mà dùng chung được, còn static method để gọi mà ko cần tạo class. Kể cả keyword extern cũng dùng nhiều trong nhiều trường hợp, chứ ko phải ko muốn dùng là ko muốn dùng.

Tham khảo thêm :

5 Likes

Tóm lại là tuỳ mục đích.
Không phải tự dưng nó sinh ra nhiều kiểu.

6 Likes

Header và extern mang ý nghĩa public, source file và static mang ý nghĩa private. Do đó khai báo biến trong header mà không muốn dùng extern thì nghe có vẻ vô lý.
Thứ 2 là không ai đi khai báo biến static trong header cả, header chỉ làm nhiệm vụ khai báo hàm hoặc cùng lắm là define các kiểu dữ liệu ( ví dụ define struct, union hay enum), còn các biến struct/union/enum này thì khai báo trong .c, ngoại trừ 1 số trương hợp quá đặc biệt, chẳng hạn bản thân length kia là 1 struct chứa đến hàng trăm bit dữ liệu và các module khác liên tục access.

Trong C người ta hay làm thê này: ( cách 1)

Khai báo biến trong common.c

static int length;

Define các hàm trong common.h

extern void Init() ; // trong này khởi tạo length, ví dụ length = 0;
extern int GetLength(); // return length
extern void SetLength( int ); // set giá trị cho length ( nếu length là data cần update )
extern void PrintSomething(); // hàm có sử dụng giá trị length

Từ đó trong main :

Init(); // length  được khởi tạo
int length = GetLength();
data = 300 - length; 
printSomething();
SetLength() ...

Ở đây length là biến global nhưng phạm vi của nó chỉ nằm trong file common.c. Các module khác muốn thao tác với nó thì thông qua các hàm define trong header, chứ không trực tiếp access.

Cách 2 : ( Nếu vẫn muốn dùng global trong header)
Có 2 khái niệm khai báo và định nghĩa

int length; // khai báo length
int length = 100; đinh nghĩa length.

Lỗi bạn gặp là multi definition, do trong header đã define length rồi. 1 biến chỉ có duy nhất 1 defition. Quá trình khởi tạo biến tạo ra definition. Khi biên dịch compiler sẽ insert nội dung của common.c/main.c vào trong common.h, nó sẽ phát hiện ra có nhiều definition của length. Muốn không bị lỗi thì header chỉ khai báo, còn trong source file include header này có 1 thằng khởi tạo nó.

int length; //header
length = 100; // common.c

Cách làm này giống như tạo ra 1 DataCenter hay DataBus, nhưng làm nó cũng giống cách 1. Tức là variable_common.h chỉ khai báo các hàm Set/Get/Clear data, còn bản thân data nên khai báo static và đặt trong variable_common.c

5 Likes

Cám ơn các bạn. Mình thấy họ viết như vậy trong mini project và không hiểu họ làm như vậy để làm gì . Mình để là không muốn dùng extern để tránh các câu trả lời mang tính chuyển chủ đề.
Ví dụ: bạn dùng extern là được.
Cái chính là mình muốn biết cách làm như trên (dùng static) nó lợi/hại như thế nào. Những lời khuyên nên dùng cái nào thì mình luôn đón nhận nhưng mình vẫn muốn biết câu trả lời trực tiếp cho câu hỏi của mình trước rồi mới tới lời khuyên có nên làm 1 cách khác không. :smiley:

3 Likes

Dùng static hay extern để lưu cái biến mà giá trị của nó có thể thay đổi và được dùng ở nhiều nơi nhiều thời điểm. Giá trị của nó ảnh hưởng tới kết quả xử lý của những nơi liên quan.
Nếu không có / dùng static/extern chắc lưu file/database rồi khi cần thì backup lại hay sao ?
Đấy là cái lợi.

Còn cái hại, thì là biến static/extern nó sẽ sống từ lúc ứng dụng chạy đến khi ứng dụng tắt. Nó sẽ luôn chiếm 1 lượng RAM nào đó để lưu nó. Nếu nó có kích thước lớn và ít dùng thì lượng RAM đó khá lãng phí.

Tuy nhiên,
Trong những trường hợp khác, dung lượng biến đó nhỏ như 1 số int, double hay 1 object vài trăm KB hoặc MB nhưng hệ thống hiện tại RAM trống cả GB thì chả ảnh hưởng gì.
Cái nguyên tắc để biến sống trong thời gian ngắn nhất và né static nó chỉ thực sự hữu dụng với những chiếc máy tính ngày xưa hoặc các ứng dụng nhúng mà lượng RAM nó rất thấp. Chỉ vài trăm byte cho đến vài trăm MB là cùng. Còn lại thì cái nguyên tắc đó được xếp sau những cái khác.

3 Likes

Ý bác là cụ thể dùng static trong trường hợp 2 vói không dùng static trong trường hợp 3 có gì lợi hại hả? Hay là lợi hại khi dùng/không dùng từ khóa static nói chung?

1 Like

biến toàn cục mà thêm static vào thì chỉ truy cập được trong file đó… Khi có từ khóa static này thì có extern ở file khác cũng ko truy cập được. Tiện dụng khi lười truyền 1 biến nào đó trong các hàm trong 1 file mà ko sợ làm bẩn global namespace

cho 1 cái hàm truy cập biến toàn cục static này thì khác gì bỏ cái static đó đi: cho phép truy cập ngoài file đó :V Mà cũng chả cần viết nó ở ngoài, để nó ở trong cái hàm đó luôn:

// static int some = 0;   // khỏi để ngoài global
int& getSome() {
    static int some = 0;
    return some;
}

còn bình thường người ta xài extern là để chỉ biến này được khai báo trong file khác, sử dụng biến đó. Có cái gì mà phải ngại ko xài, nếu đã dùng biến toàn cục :V

thiếu gì cách xài khác: cho vào làm biến static của 1 class chẳng hạn :V Ko sợ đụng tên với mấy ông khác :V

class GlobalConfig {
public:
    static const int majorVersion = 0;
    static const int minorVersion = 1;
    static std::vector<std::string> pluginPaths;
};

// trong file .cpp
std::vector<std::string> GlobalConfig::pluginPaths{};
5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?