2016-07-25 22 views
6

Tôi muốn biết liệu mã C sau tuân thủ các C99 và/hoặc tiêu chuẩn C11 (s):Iterating thông qua đối số của một hàm số bằng cách sử dụng một con trỏ đến đầu tiên một

void foo(int bar0, int bar1, int bar2) { 
    int *bars = &bar0; 

    printf("0: %d\n1: %d\n2: %d\n", bars[0], bars[1], bars[2]); 
} 

int main(int argc, char **argv) { 
    foo(8, 32, 4); 

    return 0; 
} 

Mã này biên dịch đoạn mã và chạy như mong đợi khi sử dụng visual studio 2013 và bản in:

0: 8
1: 32
2: 4

+1

Bạn đang yêu cầu thỏa mãn sự tò mò của mình hay bạn có vấn đề mà bạn cho rằng điều này sẽ giải quyết? – StoryTeller

+0

Chỉ cần ra khỏi tò mò, kể từ khi đối số variadic dường như sử dụng kỹ thuật này để lặp qua các đối số của nó. –

Trả lời

11

Không, không phải bất cứ nơi nào gần.

C tiêu chuẩn không đảm bảo rằng đối số chức năng được lưu trữ trong các vị trí bộ nhớ liên tiếp (hoặc, bất kỳ thứ tự cụ thể nào, cho rằng vấn đề). Nó tùy thuộc vào trình biên dịch và/hoặc nền tảng (kiến trúc ) để quyết định cách các đối số hàm được truyền cho hàm.

Để thêm một số chi tiết rõ ràng hơn, thậm chí không đảm bảo rằng các đối số sẽ được chuyển sẽ được lưu trữ trong bộ nhớ (ví dụ: ngăn xếp). Họ cũng có thể sử dụng các thanh ghi phần cứng (bất cứ khi nào có thể áp dụng), đối với một số hoặc tất cả các tham số, để thực hiện các thao tác nhanh. Ví dụ,

  • PowerPC

    Kiến trúc PowerPC có một số lượng lớn các thanh ghi vì vậy hầu hết các chức năng có thể vượt qua tất cả các đối số trong thanh ghi cho các cuộc gọi mức độ duy nhất. [...]

  • MIPS

    Việc phổ biến nhất được sử dụng quy ước gọi cho 32 bit MIPS là O32 ABI mà vượt qua bốn đối số đầu tiên vào một chức năng trong thanh ghi $a0 - $a3; các đối số tiếp theo được truyền trên stack. [...]

  • X86

    Kiến trúc x86 được sử dụng với nhiều công ước gọi khác nhau. Do số lượng nhỏ các thanh ghi kiến ​​trúc, các quy ước gọi x86 chủ yếu là truyền các đối số trên stack, trong khi giá trị trả về (hoặc một con trỏ tới nó) được truyền vào một thanh ghi.

v.v. Kiểm tra full wiki article here.

Vì vậy, trong trường hợp của bạn, bars[0] là một hợp lệ truy cập, nhưng dù bars[1]bars[2] là hợp lệ, phụ thuộc vào cơ bản môi trường (nền tảng/biên dịch), hoàn toàn. Tốt nhất là không dựa vào hành vi bạn mong đợi.

Điều đó nói rằng, chỉ để nitpick, trong trường hợp bạn không có ý định sử dụng các đối số (nếu có) truyền cho main(), bạn chỉ có thể giảm bớt chữ ký để int main(void) {.

+0

+1, nhưng có lẽ một nên thêm rằng trên kiến ​​trúc hiện đại, các thông số chức năng đầu tiên không được lưu trữ trong bộ nhớ ở tất cả, nhưng thông qua thanh ghi phần cứng. Và có lẽ cũng không phải là trình biên dịch quyết định, mà là API nền tảng. –

+0

@JensGustedt Sir, đã thêm một chút thông tin về mặt trận đó. Bây giờ còn tốt hơn không? –

5

Không có tiêu chuẩn hỗ trợ này. Nó cực kỳ nghịch ngợm.

Chỉ mục mảng và số học con trỏ chỉ hợp lệ đối với mảng. (Lưu ý một ngoại lệ nhỏ: bạn có thể đọc một con trỏ vượt qua một mảng hoặc một vô hướng, nhưng bạn không thể deference nó.)

7

Không, nó không tuân thủ bất kỳ tiêu chuẩn được xuất bản nào. Làm thế nào các đối số và biến cục bộ được lưu trữ, và ở đâu, là đến trình biên dịch. Những gì có thể làm việc trong một trình biên dịch có thể không hoạt động trong một trình biên dịch khác, hoặc thậm chí trên một phiên bản khác của cùng một trình biên dịch.

Đặc điểm kỹ thuật C thậm chí không đề cập đến ngăn xếp, tất cả chỉ định là quy tắc phạm vi.

+0

Chức năng biến thể cũng dường như là một phần của tiêu chuẩn - va_start, va_end là một phần của thư viện chuẩn, và đó chính xác là những gì các macro đang làm - đi qua các tham số ngăn xếp. – MichaelMoser

+3

@MichaelMoser Có, nhưng cách những macro được triển khai không có trong tiêu chuẩn. Và có một ngăn xếp không phải là một yêu cầu cho một trình biên dịch C (đặc biệt là vì nó không có trong đặc tả C), nó chỉ là chi tiết triển khai thuận tiện. –

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