2010-03-12 6 views
6

나는 그런 식으로 몇 가지 C 코드를 읽고 있어요 : 그것은 성능이 중요한 그래서C의 구조체는 효율적입니까?

double function(int lena,double xa,double ya, double za, double *acoefs, ..., 
       int lenb,double xb,double yb, double zb, double *bcoefs, ..., 
       same for c, 
       same for d) 

이 기능은 100.000 배보다 코드 MOR에 호출된다.

이 코드를 확장하기 위해 노력하고있어하지만 효율적 여부 (얼마나이 속도에 영향을 미친다) 다음이

struct PGTO { int len; double x,y,z ; double *acoefs } 

과 같은 구조체의 모든 매개 변수를 캡슐화하는 경우, 내가 알고 싶은 함수의 매개 변수에 액세스하십시오.

+11

프로파일 및 테스트 – cobbal

+1

컴파일 된 코드는 x86 및 ARM 표준 호출 규칙에서 동일해야합니다. – kennytm

+0

varargs를 나타내는 '...'또는 일부 매개 변수를 생략 했습니까? – bk1e

답변

5

Visual C++ 2008 64 비트는 호출자가 스택에 구조체 복사본을위한 공간을 할당하고 데이터 항목을 복사 한 다음 해당 복사본의 주소 만 값으로 함수에 전달하도록함으로써 구조체를 전달하는 것처럼 보입니다 .컴파일

이 간단한 예는 다음과 같다 - 그래서 기본적으로 당신은 호출자가 스택에 그들을 밀어 개별 항목을 통과 할 때

movsx eax, BYTE PTR [rcx+12] 
add eax, DWORD PTR [rcx+8] 
add eax, DWORD PTR [rcx+4] 
add eax, DWORD PTR [rcx] 
movd xmm0, eax 
cvtdq2ps xmm0, xmm0 
addss xmm0, DWORD PTR [rcx+16] 
unpcklps xmm0, xmm0 
cvtps2pd xmm0, xmm0 
ret 0 

과 기능이 상대적를 액세스 -

struct data { 
    int a; 
    int b; 
    int c; 
    char d; 
    float f; 
}; 




double f2(data d) 
{ 
    return d.a+d.b+d.c+d.d+d.f; 
} 

이에 컴파일 스택 strcuture를 전달하면 호출자는 데이터 항목을 스택의 메모리 블록에 복사 한 다음 해당 주소를 함수에 전달합니다. 함수의 주소는 함수에 상대적으로 액세스합니다.

두 번째 방법은 두 가지 더 많은 어셈블리 언어 지침을 제공합니다. 그러나 테스트에서 알 수 있듯이 두 가지 방법의 효율 차이는 몇 마이크로 초가 아닙니다. 내 모든 테스트에서 컴파일러는 어쨌든 포인터를 통해 호출하지 않으면 어쨌든 모든 호출을 인라인하려고 했으므로 아무 것도 실제 프로그램의 스택을 통해 전달되지 않을 수도 있습니다. 구조체를 사용하여 내 의견으로는

는 명확하고 성능 이상 의심의 여지 당신이 정확한 설정을 프로파일해야하는 경우 그래서, 언제나처럼 하나 :

에 대한 이동 속도에 유의 한 차이가없는 것으로 나타

5

이 질문에 대한 답변은 플랫폼 및 호출 규칙에 따라 다릅니다. 또한 함수가 인라인 될 수 있고 다른 컴파일러 최적화에 따라 달라집니다.

구조체에 대한 포인터를 전달하는 경우 스택에 복사 할 매개 변수가 더 적기 때문에 많은 플랫폼에서 구조체 버전이 더 효율적일 수 있습니다.

어쨌든 질문에 쉽게 대답 할 수 없습니다. 따라서 모든 성능 고려 사항과 마찬가지로 : 테스트 및 프로파일!

+1

구조체에 대한 포인터를 전달하면 값이 아닌 참조로 전달됩니다. –

0

현대 컴파일러는 두 경우 모두 동일한 코드를 생성 할 가능성이 큽니다. 따라서 컴파일러가 최첨단 기술이 아닌 경우 구조와 함께 얻을 수있는 유일한 (그러나 중요한) 이점은 가독성 향상입니다.

+2

아니요. 불가능합니다. 호출 규칙에서는 인수가 스택에 전달되어야합니다. 컴파일러는 함수가'static'으로 선언되지 않는 한 호출 규칙을 구부릴 수 없습니다. 그것은 일반적으로 그렇지 않습니다. –

+0

네 말이 맞아, 그걸 잊어 버렸어. –

+0

@How 구조체와 단일 매개 변수의 차이점은 무엇입니까? 두 경우 모두 매개 변수가 스택에 복사됩니다. –

0

가장 좋은 것은 프로필을 작성하고 테스트하는 것입니다.

하지만 struct에 대한 포인터를 전달할 때 더 적은 매개 변수가 스택에 복사됩니다. 또한 함수 호출이 더 깔끔 해 보일 수도 있습니다.

4

우선 구조체를 사용하는 것이 정확한 경우 인 것으로 보입니다. 코드는 읽기 쉽고 이해하기 쉽기 때문에 복잡해지지 않습니다.

구조체에 포인터를 전달하는 것은 일반적으로 많은 매개 변수를 전달하는 것보다 저렴합니다.

+3

함수를 호출 할 때마다 구조체를 채울 필요는 없습니다. – lhf

+0

물론,하지만 다시 한번, 호출 코드와 나머지 소스에 의존합니다. 고려해야 할 요소가 충분히 있습니다. –

0

예, 있습니다. 내가 그만큼 돈을 벌면 100 만 달러를 낼 것이고 성능 차이는 미미할 것이다.

0

구조체 또는 인수 목록을 전달하면 큰 차이가 없어야합니다. 호출 규칙에 따라 값으로 전달되고 스택을 통해 전달되어야합니다 (함수를 선언 할 수있는 경우가 아니면 static).

참조로 전달할 수 있도록 코드를 리팩터링하여 구조체에 대한 포인터를 전달할 수 있습니다. 하지만 아마도 코드를 좀 더 복잡하고 덜 읽을 수있게 만드는 중요한 재 설계 일 것입니다.

+0

"통화 규칙"은 모든 통화 규칙을 의미합니까? 네가 본 모든 호출 규칙들? 'cdecl' 호출 규칙? –

1

나는 구조체를 얼마나 자주 채워야하는지에 달려 있다고 생각한다.

구조체 (4 바이트)에 단일 포인터를 전달하면 int, 3 개의 double 및 포인터 (32 바이트)를 전달하는 것보다 명령어가 적게 들지만 명령어를 수행하기 전에 32 바이트로 구조체를 채워야하는 경우 전화를 걸면 이점을 잃어 버렸습니다.

성능은 항상 상대적입니다. 따라서 가치가 있는지 여부를 확인하는 유일한 방법은 해당 인수를 전달하는 데 소요 된 시간의 백분율을 확인하는 것입니다. 그렇게하기 위해서, 나는 그것을 달리고 그것을 무작위로 10 또는 20 번 중단한다. 내가 그 논쟁을 통과하는 시간의 10 % 이상을 잡아 내지 않으면, 먼저 해결 될 수있는 더 큰 문제가있을 수 있습니다.

관련 문제