2013-09-05 29 views
13

Quan sát sau đây xuất hiện khi tôi đang theo dõi this question về các sự khác biệt char[]char*.Tại sao char [] và char * là typedefs khác nhau, nhưng đôi khi ... không?

#include <iostream> 

typedef char ar[]; 
typedef char* pr; 
void f2(ar x, pr y) 
{ 
    std::cout << std::is_same<decltype(x), decltype(y)>::value << '\n'; 
    std::cout << std::is_same<ar, pr>::value << '\n'; 
} 

int main() 
{ 
    char data[] = "data"; 
    char *ptr = data; 
    f2(data,ptr); 
    return 0; 
} 

Output (trên Apple LLVM phiên bản 4.2 (vang-425.0.28))

1 
0 

Tại sao loại những báo cáo như là khác nhau, nhưng không khác nhau decltype() s? Sự nghi ngờ của tôi là trên thực tế, các loại khác nhau do khai báo typedef của họ, nhưng tại sao các biến được báo cáo là cùng loại?

+0

Phân hủy? (như tham số chức năng) – dyp

+1

(Tham gia vào bình luận của tôi :) Các kiểu tham số của hàm được "phân rã" theo [dcl.fct]/5: "Sau khi xác định kiểu của mỗi tham số, bất kỳ tham số nào kiểu" mảng của ' T' ”hoặc“ hàm trả về 'T'” được điều chỉnh thành “con trỏ tới' T' ”hoặc“ con trỏ tới hàm trả về 'T'”, tương ứng ”. Do đó 'decltype (x)' là * trỏ tới 'char' *, không * mảng không xác định ràng buộc của' char' * (không giống 'ar'). – dyp

+0

@DyP Cảm ơn bạn đã tham khảo tiêu chuẩn, thưa sếp. – WhozCraig

Trả lời

20

Trong C++, như trong C, tham số được khai báo kiểu mảng là được điều chỉnh (tại thời gian biên dịch) thành loại con trỏ, cụ thể là con trỏ đến loại phần tử của mảng.

Điều này xảy ra cho dù loại mảng được chỉ định trực tiếp hoặc thông qua typedef (hãy nhớ rằng typedef không tạo loại mới, chỉ là bí danh cho loại hiện có).

Vì vậy, đây:

typedef char ar[]; 
typedef char* pr; 
void f2(ar x, pr y) 
{ 
    // ... 
} 

thực sự có nghĩa là:

void f2(char* x, char* y) 
{ 
    // ... 
} 

Một quy tắc, cũng chia sẻ bởi C và C++, đó là một biểu kiểu mảng là, trong hầu hết nhưng không phải tất cả các ngữ cảnh, được ngầm định chuyển đổi thành con trỏ thành phần tử đầu tiên của đối tượng mảng. Điều đó có nghĩa rằng nếu bạn xác định một đối tượng mảng:

char arr[10]; 

bạn có thể sử dụng tên của đối tượng đó như một cuộc tranh cãi với một chức năng mà phải mất một tham số char* (mà mất các giới hạn thông tin).

Trong C, các trường hợp chuyển đổi ngầm này không xảy ra là:

  1. Khi biểu thức mảng là các toán hạng của sizeof (sizeof arr mang lại kích thước của mảng, không phải là kích thước của một con trỏ);
  2. Khi biểu thức mảng là toán hạng của đơn nhất & (&arr là một con trỏ tới mảng, không phải là con trỏ đến con trỏ); và
  3. Khi biểu thức mảng là một chuỗi ký tự được sử dụng để khởi tạo một đối tượng kiểu mảng (char s[] = "hello"; khởi tạo s làm mảng, không phải là con trỏ).

Không ai trong số những trường hợp này (hoặc các trường hợp khác xảy ra trong C++) xuất hiện trong chương trình của bạn, vì vậy cuộc gọi của bạn:

f2(data,ptr); 

qua hai giá trị con trỏ kiểu char*-f2.

Bên f2, tham số đối tượng xy đều là kiểu char*, vì vậy std::is_same<decltype(x), decltype(y)>::value là đúng.

Nhưng các loại arpr là khác biệt. ar là loại mảng không đầy đủ char[]pr là loại con trỏ char*.

Điều này giải thích kết quả của chương trình của bạn. Sự kỳ quặc xảy ra vì tham số x, mà bạn đã xác định với loại mảng ar, thực sự thuộc loại char*, cùng loại với pr.

+0

Cảm ơn, Keith. Điều này đã được trình bày rất tốt, và trong buổi hòa nhạc với tham khảo chuẩn của Dyp từ bình luận chung, giải thích chính xác những gì đang được nhìn thấy. Rất nhiều đánh giá cao. – WhozCraig

2

Họ C là giá trị theo giá trị và giá trị C của một mảng là con trỏ đến phần tử đầu tiên của nó. Khi bạn vượt qua một mục được khai báo là một mảng cho một hàm, những gì thực sự nhận được thông qua là con trỏ đó, và C xử lý nguyên mẫu như thể bạn đã khai báo nó theo cách đó.

1

Tôi đã thay đổi mã để chúng tôi có thể biết cách gọi f2 thay đổi loại. Trước khi gọi các biến có kiểu khác nhau. Sau khi gọi họ đã trở thành cùng

typedef char ar[]; 
typedef char* pr; 
void f2(ar x, pr y) 
{ 
    cout << is_same<decltype(x), decltype(y)>::value << '\n'; //same type 
} 

int main() 
{ 
    ar data = "data"; 
    pr ptr = data; 
    cout << is_same<decltype(data), decltype(ptr)>::value << '\n'; // different 
    f2(data,ptr); 
    return 0; 
} 

đầu ra là .Như @jthill, @Dyp và @keith Thompson nói điều này là do mục nát của mảng để con trỏ.

+1

Một "trực quan hóa" khác của vấn đề: 'is_same ' và 'is_same ' bên trong 'f2' (và dĩ nhiên' is_same '). – dyp

+1

Ồ, và một cái gì đó thú vị: 'is_same ' cũng là 'false' (vì' ar' không đầy đủ và [basic.types]/6 nói chúng khác nhau). – dyp

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