2017-07-23 54 views
8

C nie może zwracać odwołań w przeciwieństwie do C++. Czy to oznacza, że ​​jeśli uzyskasz dostęp do A[i], to skopiujesz element do oceny wyrażenia?Czy C kopiuje element za każdym razem, gdy uzyskujesz dostęp do tablicy?

Na przykład jeśli A jest tablicą 10 int s, ma A[5]+=1; zwiększamy tylko tymczasową kopię zbudowany przy ocenie A[5], w przeciwieństwie do wektora C++ 's, które spowodują przyrost rzeczywisty sam element szósty?

+14

'a [5] 'dereferences elementu tablicy, bezpośrednio, bez tymczasowych kopie zaangażowane. – user0042

+0

'A [5] + = 1' zwiększa element z tablicy" A "o współczynnik zero. Jeśli tego nie zrobi, kompilator ma błąd. Niejasne, o co pytasz. – EJP

+0

'A [5] + = 1' jest takie samo jak' A [5] = A [5] + 1', kompilator optymalizacyjny wykonałby jak najmniej kopii, jeśli w ogóle, może być wyrażony przez język maszyny. – nos

Odpowiedz

12

C ma koncepcję zwaną "lwartością", która jest podobna do referencji. Nie jest typem (nie jest częścią systemu typów), ale niektóre wyrażenia C są "lwartościami", a tylko takie wyrażenia mogą być lewym operandem przypisania (w tym op-assign) lub inkrementacją/dekrementacją.

Ponieważ C nie ma przeciążenia operatora, nie ma potrzeby wprowadzania rozróżnienia w systemie typów, ponieważ nigdy nie ma potrzeby deklarowania rzeczy jako wartości r kontra versus l. Chęć dodania operatorów w C++ prowadziło do wprowadzenia typów referencyjnych, aby odróżnić rvalue/lvalue dla przeciążonych operatorów.

5

Jeśli to prawda, w ogóle nie można modyfikować tablic, a wyrażenie A[5]+=1; nie przyniesie efektu!

Z drugiej strony, po przekazaniu argumentu skalarnego do funkcji zachowuje się jak kopia, ponieważ nie jest modyfikowana po powrocie. Ale tablica, w rzeczywistości przekazana jako wskaźnik, nie jest kopiowana (co byłoby nieznośnie kosztowne) i może się różnić po powrocie.

2

C zawsze skopiowanie element przy odczytu z tablicy z A[i], to znaczy, gdy ekspresja A[i] jest „RValue”. Jednakże biorąc pod uwagę pisze, C ma pojęcia „lwartości” wyrażeń, które są zasadniczo ograniczony podzbiór składni wyrażeń, które mogą pojawić się jako cel cesji:

X = Y 
*X = Y 
X[i] = Y 
X.n = Y 

W tych przypadkach, "wyrażenia" nie są w rzeczywistości wartościowane - mają tę samą składową, co dla wygody, ale nie są takie same, ale nie są takie same. Można myśleć o nich jako coś więcej jak poniżej:

memcpy(&X, &Y, sizeof(Y)); 
memcpy(&*X, &Y, sizeof(Y)); 
memcpy(&X[i], &Y, sizeof(Y)); 
memcpy(&X.n, &Y, sizeof(Y)); 

Lub alternatywnie myśleć C jako mający wielu różnych operatorów przypisania:

_ = _ // direct assignment 
*_ = _ // indirect assignment 
_[_] = _ // special case of indirect assignment 
_._ = _ // special case of indirect assignment 

czy inaczej, zadanie takie jak A[5] += 1 zwiększy wartość szóstego elementu A w miejscu, dokładnie tak, jak można się spodziewać, co można zweryfikować tak:

int A[1] = { 1 }; 
A[0] += 5; 
printf("%d\n", A[0]); // 6 
4

ma A [5] + = 1; tylko zwiększyć czasowego kopiowaniem przy ocenie [5]

nr A[5]+=1; spowoduje 6. element A być zwiększane o 1.

Najprawdopodobniej zostanie to osiągnięte poprzez skopiowanie A[5] do rejestru w CPU, zwiększenie go i skopiowanie wartości z powrotem.

Oto program:

int main(){ 
    int A[10]; 
    A[5]+=1; 
    return 0; 
} 

oto gcc generowane x86-64 asemblera dla A[5]+=1;

mov  eax, DWORD PTR [rbp-28] 
    add  eax, 1 
    mov  DWORD PTR [rbp-28], eax 

który porusza DWORD PTR [rbp-28] w 32-bitowym EAX akumulatorze, dodaje 1 do niego i przenosi go z powrotem w to samo miejsce.

identyfikuje 6. element A przez jego położenie względem (końca) ramki stosu (rbp).

Punkt dotyczący referencji to czerwony-śledzia. Zarówno C jak i C++ kompilują się do kodu maszynowego (prawdopodobnie poprzez asembler). Jakie inne funkcje języków nie mają wpływu na interpretację lub kompilację A[5]+=1;.

0

nie, indeks tablicy i jest po prostu wskaźnikiem, więc tylko cała lokalizacja jest przekazywana zamiast całej tablicy, a wpływa ona na wartość rzeczywistej lokalizacji pamięci.

próby następujący kod:

#include<stdio.h> 
void function(int[]); 
int main() 
{ 
    int a[] = {0,1,2,3,4,5,6,7,8,9}; 
    int i; 
    for(i = 0; i < 10; i++) 
     printf("%d, ",a[i]);  
    function(a); 
    printf("\n"); 
    for(i = 0; i < 10; i++) 
     printf("%d, ",a[i]); 
    return 0; 
} 

void function(int b[]) 
{ 
    int i; 
    for(i = 0; i < 10; i++) 
     b[i] *= 10; 
} 

OUTPUT