2015-07-09 16 views
14

Ai đó có thể vui lòng làm rõ liệu (và tại sao) một chức năng có thể được quy cho pure hoặc const nếu nó có tham số con trỏ.GCC tinh khiết/const chức năng chấp nhận một đối số con trỏ

Theo GCC documentation:

Một số ví dụ phổ biến của các chức năng thuần túy là strlen hoặc memcmp.

Toàn bộ điểm của hàm thuần túy là chỉ cần được gọi một lần cho cùng một tham số, tức là kết quả có thể được lưu trong bộ nhớ cache nếu trình biên dịch cho rằng nó phù hợp để làm như vậy, tuy nhiên cách này hoạt động với memcmp?

ví dụ:

char *x = calloc(1, 8); 
char *y = calloc(1, 8); 

if (memcmp(x, y, 8) > 0) 
    printf("x > y\n"); 

x[1] = 'a'; 
if (memcmp(x, y, 8) > 0) 
    printf("x > y\n"); 

Các thông số cuộc gọi thứ hai để memcmp là giống hệt nhau để là người đầu tiên (các con trỏ trỏ đến cùng một địa chỉ), làm thế nào để trình biên dịch biết không sử dụng kết quả từ đầu tiên gọi, nếu memcmp là tinh khiết?

Trong trường hợp của tôi, tôi muốn chuyển mảng tới hàm thuần túy và tính kết quả dựa trên mảng. Ai đó trấn an tôi rằng điều này là ổn, và khi giá trị trong mảng thay đổi nhưng địa chỉ thì không, hàm của tôi sẽ được gọi chính xác.

Trả lời

3

Đối với thuần túy, chúng ta có thể thấy từ bài viết Implications of pure and constant functions rằng thuần túy có nghĩa là hàm không có tác dụng phụ và chỉ phụ thuộc vào các tham số. Vì vậy, nếu trình biên dịch có thể xác định rằng các đối số là như nhau và bộ nhớ không thay đổi giữa các cuộc gọi tiếp theo, nó có thể loại bỏ các cuộc gọi tiếp theo đến hàm thuần túy vì nó biết hàm thuần túy không có tác dụng phụ. Điều này có nghĩa là trình biên dịch phải phân tích để có thể xác định xem các đối số cho hàm thuần túy có thể đã được sửa đổi trước khi nó có thể quyết định loại bỏ các cuộc gọi tiếp theo sang một hàm thuần túy cho cùng một đối số hay không.

Một ví dụ từ bài báo như sau:

int someimpurefunction(int a); 
int somepurefunction(int a) 
    __attribute__((pure)); 

int testfunction(int a, int b, int c, int d) { 

    int res1 = someimpurefunction(a) ? someimpurefunction(a) : b; 
    int res2 = somepurefunction(a) ? somepurefunction(a) : c; 
    int res3 = a+b ? a+b : d; 

    return res1+res2+res3; 
} 

và nó cho thấy việc lắp ráp tối ưu hóa được tạo ra trong đó cho thấy rằng somepurefunction chỉ gọi một lần và sau đó nói:

Như bạn có thể thấy, hàm thuần túy được gọi chỉ một lần, bởi vì hai tham chiếu bên trong toán tử bậc ba là tương đương, trong khi hàm kia được gọi hai lần. Điều này là do không có thay đổi đối với bộ nhớ toàn cầu được biết đến với trình biên dịch giữa hai hàm gọi của hàm thuần túy (chính hàm này không thể thay đổi nó - lưu ý rằng trình biên dịch sẽ không bao giờ đưa đa luồng vào tài khoản, ngay cả khi yêu cầu cho nó một cách rõ ràng thông qua cờ -pthread), trong khi chức năng không thuần khiết được phép thay đổi bộ nhớ toàn cầu hoặc sử dụng các hoạt động I/O.

Logic này cũng áp dụng cho một con trỏ, vì vậy nếu trình biên dịch có thể chứng minh bộ nhớ chỉ vào con trỏ chưa được sửa đổi sau đó nó có thể loại bỏ các cuộc gọi đến chức năng tinh khiết như vậy trong trường hợp của bạn khi trình biên dịch thấy:

x[1] = 'a'; 

nó không thể loại bỏ lệnh gọi thứ hai thành memcmp vì bộ nhớ được chỉ định bởi x đã thay đổi.

+1

Cảm ơn bạn đã liên kết bài viết, thú vị. Nhưng câu hỏi của tôi là cụ thể về các đối số con trỏ tới các hàm thuần túy. – jsj

+0

@ trideceth12 phân tích tương tự cũng áp dụng cho con trỏ. –

+0

Vậy điều gì xảy ra nếu 8 và 1 không được biết tại thời gian biên dịch? Ví dụ. chúng biến đổi? – Kata

3

Nếu tôi hiểu tài liệu chính xác, chức năng pure có thể phụ thuộc vào giá trị của bộ nhớ, nơi trình biên dịch biết khi nào bộ nhớ thay đổi. Hơn nữa, một hàm pure không thể thay đổi trạng thái của chương trình, chẳng hạn như một biến toàn cầu, nó chỉ tạo ra một giá trị trả về.

Trong mã ví dụ của bạn, memcmp có thể là hàm pure. Trình biên dịch thấy rằng bộ nhớ được thay đổi giữa các cuộc gọi đến memcmp và không thể sử dụng lại kết quả của cuộc gọi đầu tiên cho cuộc gọi thứ hai.

Mặt khác, memcmp có thể không được khai báo là hàm const, vì nó phụ thuộc vào dữ liệu trong bộ nhớ. Nếu nó là const, trình biên dịch có thể áp dụng tối ưu hóa tích cực hơn.

Vì lý do này, có vẻ như an toàn để khai báo hàm mà bạn muốn triển khai dưới dạng pure (nhưng không phải const).

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