2013-09-26 131 views
11

Có cách nào để nói với trình biên dịch C99 rằng cách duy nhất tôi sẽ truy cập mảng đã cho là sử dụng myarray [index]? Nói cái gì đó như thế này:Sử dụng giới hạn với mảng?

int heavy_calcualtions(float* restrict range1, float* restrict range2) 
{ 
    float __I promise I won't alias this__ tmpvalues[1000] = {0}; 

    .... 
    heavy calculations using range1, range2 and tmpvalues; 
    .... 
} 

Bằng việc sử dụng hạn chế Tôi đã hứa rằng tôi sẽ không RANGE1 bí danh và RANGE2 nhưng làm thế nào để làm điều tương tự cho mảng được khai báo bên trong hàm của tôi?

+0

Loại cảnh báo nào sẽ ném? – dhein

+1

"sử dụng không hợp lệ các giới hạn" - nó được cho là được sử dụng với con trỏ, không phải mảng (theo như tôi hiểu). Tôi có thể làm nổi * hạn chế tmpvalues ​​= malloc (sizeof (float) * 1000) nhưng sau đó tôi không phân bổ trên stack có thể ảnh hưởng đến hiệu suất là tốt. Bên cạnh việc nói với một trình biên dịch truy cập vào các chỉ mục mảng là an toàn (vì vậy không cần đọc phòng thủ) có vẻ như phần mở rộng tự nhiên hạn chế sử dụng với con trỏ, vì vậy trực giác phải có cách để làm điều đó. –

+1

Tôi đã làm: float * limits tmpvalues ​​= alloca (sizeof (float) * 1000); memset (tmpvalues, 0, sizeof (float) * 1000); và đó là cải tiến có thể đo lường nhưng tôi thích làm nó trong tiêu chuẩn (như trong cách khiếu nại C99) –

Trả lời

3

Tại sao bạn không thể làm như sau? Bạn không truy cập dữ liệu được liên kết với tmpvalues qua biến đó, do đó, nó hợp lệ để sử dụng một con trỏ giới hạn trong phần tính toán chuyên sâu của mã.

#include <stdio.h> 
#include <stdlib.h> 

int heavy_calcs(int n, float* restrict range1, float* restrict range2) 
{ 
    if (n>1000) return 1; 
    float tmpvalues[1000] = {0}; 
    { 
     float * restrict ptv = tmpvalues; 
     for (int i=0; i<n; i++) { 
      ptv[i] = range1[i] + range2[i]; 
     } 
    } 
    return 0; 
} 

int main(int argc, char * argv[]) 
{ 
    int n = (argc>1) ? atoi(argv[1]) : 1000; 
    float * r1 = (float*)malloc(n*sizeof(float)); 
    float * r2 = (float*)malloc(n*sizeof(float)); 
    int rc = heavy_calcs(n,r1,r2); 
    free(r1); 
    free(r2); 
    return rc; 
} 

Tôi đã chạy điều này thông qua trình biên dịch Intel 15 và không gặp sự cố khi vectơ vòng lặp. Cấp, vòng lặp này là tầm thường so với những gì tôi cho là của bạn, vì vậy số dặm của bạn có thể thay đổi.

+0

[Không cần phải bỏ kết quả của 'malloc' trong C] (http: // stackoverflow.com/q/605845/995714) –

+1

Không cần phải có '{}' xung quanh việc phân công 'ptv'. – Jeff

10

Mặc dù câu trả lời của Jeff là đúng, nghĩa là bạn luôn có thể làm cho một con trỏ đến mảng phân bổ, thực tế là trình biên dịch biết tại thời gian biên dịch rằng tmpvalues ​​sẽ không được aliased vì biến được khai báo là một mảng thực tế, không phải là một con trỏ. Các cơ hội duy nhất để bí danh một mảng là khai báo một con trỏ đến nó, vì vậy nếu bạn không làm điều đó, không cần phải khai báo nó là restrict. Điều này hiển nhiên hơn nếu tmpvalues là biến duy nhất bạn sẽ có trong hàm.

Sự cố có thể phát sinh nếu bạn chuyển con trỏ đến một hàm khác, khi đó bạn nên nêu rõ con trỏ đã nhận có bị hạn chế hay không.

Các tài liệu tôi gặp phải liên quan đến chủ đề này bao gồm các C99:

Cho D là một lời tuyên bố của một định danh thường cung cấp một phương tiện của chỉ định một đối tượng P như một con trỏ hạn chế trình độ gõ T .

Lưu ý rằng nó chỉ áp dụng cho con trỏ.

This other document từ TI cung cấp một số gợi ý điều chỉnh hiệu suất bằng cách sử dụng từ khóa restrict. Ngoài tất cả các gợi ý, phần 3.3 cung cấp các ví dụ khi có thể áp dụng loại vòng loại này và khi nào thì không. Tìm kiếm khai báo mảng x ở giữa trang 16, nó tuyên bố rằng nó không khai báo một con trỏ và do đó không thể là restrict -qualified.

+0

Nếu một con trỏ tới mảng được chuyển tới mã bên ngoài, không có cách nào rõ ràng để chỉ ra rằng mã bên ngoài sẽ không giữ một bản sao của con trỏ và sử dụng bản sao đó cho các mục đích tùy ý vào lần sau khi mã bên ngoài được gọi. IMHO sẽ rất hữu ích cho C có trình độ tương tự 'giới hạn' nhưng để sử dụng với các biến có địa chỉ đã được sử dụng nhưng sẽ chỉ được sử dụng theo những cách rất hạn chế, nhưng không có tính năng nào được xác định. – supercat

+0

@supercat là một vấn đề - làm thế nào để bạn xác định những 'cách khác nhau'? gcc có các thuộc tính (chẳng hạn như 'thuần') có thể được gắn vào các hàm, hứa hẹn rằng hàm sẽ không thực hiện các lớp thứ nhất định. Ngoài ra, bây giờ chúng ta có 'tối ưu hóa thời gian liên kết', nơi bộ công cụ biên dịch về cơ bản có thể xem xét chức năng thực sự đang làm và sử dụng thông tin đó. – greggo

+0

@greggo: Nếu tôi đang viết các quy tắc, tôi sẽ nói rằng một đối tượng đủ điều kiện 'register' chỉ có thể có địa chỉ của nó trong việc đánh giá đối số hàm và hành vi sẽ chỉ được xác định trong trường hợp tất cả việc sử dụng kết quả con trỏ hoặc con trỏ xuất phát từ trước khi hàm trả về, và trong khi thực thi hàm hoặc (1) đối tượng được truy cập độc quyền thông qua con trỏ kết quả hoặc con trỏ khác, hoặc (2) đối tượng không được sửa đổi thông qua bất kỳ phương tiện nào. Nếu quá trình xây dựng bắt đầu bằng cách xây dựng danh sách tất cả các biểu tượng bên ngoài được sử dụng trong mỗi hàm ... – supercat