#define so với const trong Objective-C


81

Tôi là người mới sử dụng Objective-C và tôi có một số câu hỏi liên quan đến constchỉ thị tiền xử lý #define.

Đầu tiên, tôi thấy rằng không thể xác định kiểu của hằng số bằng cách sử dụng #define. Tại sao vậy?

Thứ hai, có bất kỳ lợi ích nào khi sử dụng một trong số chúng so với một trong số chúng không?

Cuối cùng, cách nào hiệu quả hơn và / hoặc an toàn hơn?

Câu trả lời:


107

Đầu tiên, tôi nhận thấy rằng không thể xác định loại hằng số bằng #define, tại sao vậy?

Tại sao là gì? Nó không đúng:

#define MY_INT_CONSTANT ((int) 12345)

Thứ hai, có bất kỳ lợi ích nào khi sử dụng một trong số chúng so với một trong số chúng không?

Đúng. #defineđịnh nghĩa một macro được thay thế ngay cả trước khi bắt đầu biên dịch. constchỉ sửa đổi một biến để trình biên dịch sẽ gắn cờ lỗi nếu bạn cố gắng thay đổi nó. Có những ngữ cảnh mà bạn có thể sử dụng #definenhưng bạn không thể sử dụng a const(mặc dù tôi đang cố gắng tìm một ngữ cảnh bằng cách sử dụng clang mới nhất). Về lý thuyết, một constchiếm không gian trong tệp thực thi và yêu cầu tham chiếu đến bộ nhớ, nhưng trên thực tế, điều này là không đáng kể và có thể được tối ưu hóa bởi trình biên dịch.

consts thân thiện với trình biên dịch và trình gỡ lỗi hơn #define s. Trong hầu hết các trường hợp, đây là điểm quan trọng mà bạn nên cân nhắc khi đưa ra quyết định sử dụng cái nào.

Chỉ nghĩ về một ngữ cảnh mà bạn có thể sử dụng #definenhưng không const. Nếu bạn có một hằng số mà bạn muốn sử dụng trong nhiều .ctệp, với một hằng số , #definebạn chỉ cần dán nó vào tiêu đề. Với một, constbạn phải có định nghĩa trong tệp C và

// in a C file
const int MY_INT_CONST = 12345;

// in a header
extern const int MY_INT_CONST;

trong tiêu đề. MY_INT_CONSTkhông thể được sử dụng làm kích thước của mảng phạm vi tĩnh hoặc toàn cục trong bất kỳ tệp C nào ngoại trừ tệp được định nghĩa trong đó.

Tuy nhiên, đối với các hằng số nguyên, bạn có thể sử dụng một enum. Trên thực tế, đó là điều mà Apple gần như luôn làm. Điều này có tất cả các ưu điểm của cả #defines và consts nhưng chỉ hoạt động đối với các hằng số nguyên.

// In a header
enum
{
    MY_INT_CONST = 12345,
};

Cuối cùng, cách nào hiệu quả hơn và / hoặc an toàn hơn?

#definelà hiệu quả hơn về mặt lý thuyết mặc dù, như tôi đã nói, các trình biên dịch hiện đại có lẽ đảm bảo có rất ít sự khác biệt. #definean toàn hơn ở chỗ nó luôn là lỗi trình biên dịch khi cố gắng gán cho nó

#define FOO 5

// ....

FOO = 6;   // Always a syntax error

consts có thể bị lừa để được gán mặc dù trình biên dịch có thể đưa ra cảnh báo:

const int FOO = 5;

// ...

(int) FOO = 6;     // Can make this compile

Tùy thuộc vào nền tảng, việc gán vẫn có thể không thành công trong thời gian chạy nếu hằng số được đặt trong phân đoạn chỉ đọc và hành vi chính thức không được xác định theo tiêu chuẩn C.

Cá nhân, đối với các hằng số nguyên, tôi luôn sử dụng enums cho các hằng số kiểu khác, tôi sử dụng consttrừ khi tôi có lý do chính đáng để không.


Tôi biết nó đã cũ, nhưng một trường hợp bạn không thể sử dụng hằng số mà bạn có thể sử dụng định nghĩa là "#define MY_NSNUM_CONSTANT @ 5" không thể thực hiện được bằng cách sử dụng "NSNumber * const MY_NSNUM_CONSTANT = @ 5"
shortstuffsushi

Tôi sẽ tranh luận rằng #define chiếm nhiều không gian hơn trong tệp thực thi so với const. Hằng số được lưu trữ một lần, nhưng #define được nhân lên mỗi khi bạn sử dụng vì nó chỉ là sự thay thế văn bản. Nhưng vì sự khác biệt là không đáng kể nên tôi không cần thiết.
Ryan Ballantyne

@RyanBallantyne Tôi nghĩ rằng bạn có thể đúng với những thứ như hằng số chuỗi, nhưng không đúng với hằng số nguyên vì ngay cả khi bạn lưu trữ hằng số ở một nơi, để truy cập nó, bạn cần địa chỉ của nó ít nhất là lớn bằng một int. Tuy nhiên, tôi sẽ rất ngạc nhiên nếu nó tạo ra bất kỳ sự khác biệt nào trong một trình biên dịch hiện đại.
JeremyP

16

Từ một C coder:

A constchỉ đơn giản là một biến mà nội dung của nó không thể thay đổi được.

#define name value, tuy nhiên, là một lệnh tiền xử lý thay thế tất cả các trường hợp của namewith value.

Ví dụ: nếu bạn #define defTest 5, tất cả các phiên bản defTesttrong mã của bạn sẽ được thay thế bằng 5khi bạn biên dịch.


11

Điều quan trọng là phải hiểu sự khác biệt giữa các lệnh #define và const không có nghĩa giống nhau.

const

constđược sử dụng để tạo một đối tượng từ kiểu được hỏi sẽ là hằng số sau khi được khởi tạo. Nó có nghĩa là nó là một đối tượng trong bộ nhớ chương trình và có thể được sử dụng dưới dạng chỉ đọc. Đối tượng được tạo ra mỗi khi chương trình được khởi chạy.

#define

#defineđược sử dụng để dễ đọc mã và các sửa đổi trong tương lai. Khi sử dụng định nghĩa, bạn chỉ che dấu một giá trị đằng sau tên. Do đó, khi làm việc với một hình chữ nhật, bạn có thể xác định chiều rộng và chiều cao với các giá trị tương ứng. Sau đó, trong mã, nó sẽ dễ đọc hơn vì thay vì các số sẽ có tên.

Nếu sau này bạn quyết định thay đổi giá trị cho chiều rộng, bạn sẽ chỉ phải thay đổi nó trong định nghĩa thay vì tìm / thay thế nhàm chán và nguy hiểm trong toàn bộ tệp của bạn. Khi biên dịch, bộ tiền xử lý sẽ thay thế tất cả tên đã xác định bằng các giá trị trong mã. Do đó, không mất thời gian khi sử dụng chúng.


7

Ngoài nhận xét của những người khác, các lỗi sử dụng #definenổi tiếng là khó gỡ lỗi vì bộ xử lý tiền xử lý giữ chúng trước trình biên dịch.


3

Vì các chỉ thị của bộ xử lý trước không được chấp nhận, tôi khuyên bạn nên sử dụng một const. Bạn không thể chỉ định loại có bộ xử lý trước vì chỉ thị bộ xử lý trước được giải quyết trước khi biên dịch. Vâng, bạn có thể, nhưng một cái gì đó như:

#define DEFINE_INT(name,value) const int name = value;

và sử dụng nó như

DEFINE_INT(x,42) 

mà sẽ được trình biên dịch coi là

const int x = 42;

Đầu tiên, tôi nhận thấy rằng không thể xác định loại hằng số bằng #define, tại sao vậy?

Bạn có thể xem đoạn mã đầu tiên của tôi.

Thứ hai, có bất kỳ lợi ích nào khi sử dụng một trong số chúng so với một trong số chúng không?

Nói chung, có một constchỉ thị thay vì bộ xử lý trước sẽ giúp gỡ lỗi, không nhiều trong trường hợp này (nhưng vẫn có).

Cuối cùng, cách nào hiệu quả hơn và / hoặc an toàn hơn?

Cả hai đều hiệu quả. Tôi muốn nói vĩ mô có thể có khả năng được an toàn hơn vì nó không thể thay đổi trong thời gian chạy, trong khi một biến thể.


Tại sao chỉ nhập const ...vào thay vì sử dụng macro?
Ed Heal

1
@EdHeal không. Tôi chỉ nói rằng bạn có thể trả lời "Tôi thấy rằng không thể xác định loại hằng số bằng cách sử dụng #define, tại sao lại như vậy?"
Luchian Grigore

1
> pre-processor directives are frowned upon[cần dẫn nguồn]
Ben Leggiero

Tôi nghĩ bạn có thể sử dụng một kiểu như thế này: #define myValue ((double) 2). Theo tôi hiểu, bộ tiền xử lý sẽ chỉ thay thế "myValue" bằng những gì đứng sau nó trong câu lệnh xác định, bao gồm cả thông tin loại.
vomako

1

Tôi đã sử dụng #define trước đây để giúp tạo nhiều phương thức hơn từ một phương thức như nếu tôi có điều gì đó tương tự.

 // This method takes up to 4 numbers, we don't care what the method does with these numbers.
 void doSomeCalculationWithMultipleNumbers:(NSNumber *)num1 Number2:(NSNumber *)num2 Number3:(NSNumber *)num23 Number3:(NSNumber *)num3;

Nhưng tôi cũng phải làm gì để có một phương thức chỉ nhận 3 số và 2 số, vì vậy thay vì viết hai phương thức mới, tôi sẽ sử dụng cùng một phương thức bằng cách sử dụng #define, như vậy.

 #define doCalculationWithFourNumbers(num1, num2, num3, num4) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), (num4))

 #define doCalculationWithThreeNumbers(num1, num2, num3) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), nil)

 #define doCalculationWithTwoNumbers(num1, num2) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), nil, nil)

Tôi nghĩ rằng đây là một điều khá thú vị để có, tôi biết bạn có thể đi thẳng vào phương pháp và chỉ cần đặt nil vào những khoảng trống mà bạn không muốn nhưng nếu bạn đang xây dựng một thư viện thì nó rất hữu ích. Ngoài ra đây là cách

     NSLocalizedString(<#key#>, <#comment#>)
     NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
     NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)

được thực hiện.

Trong khi tôi không tin bạn có thể làm điều này với hằng số. Nhưng hằng số có những lợi ích hơn so với #define như bạn không thể chỉ định một loại với #define vì nó là một chỉ thị tiền xử lý được giải quyết trước khi biên dịch và nếu bạn gặp lỗi với #define thì chúng sẽ khó gỡ lỗi hơn các hằng số. Cả hai đều có những lợi ích và nhược điểm nhưng tôi sẽ nói rằng tất cả phụ thuộc vào lập trình viên mà bạn quyết định sử dụng. Tôi đã viết một thư viện với cả chúng bằng cách sử dụng #define để thực hiện những gì tôi đã trình bày và các hằng để khai báo các biến hằng số mà tôi cần chỉ định một kiểu trên đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.