2013-02-05 2 views
2

변수 arguement 함수가 struct/class에 대해 어떻게 객체를 사용합니까? 예 : 여기 CString::Formatvar arg 함수에 객체 전달

CString a_csName; 
CString a_csAge(_T("20")); 
a_csName.Format(_T("My Age is : %s"),a_csAge); 

CString 객체 소요의 printf 스타일 아규먼트 변수의 함수이다. 이것이 어떻게 가능한지? 에서

+0

가변적 인 템플릿을 사용하는 CString :: Format입니까? CString은 char에 대한 포인터 인 하나의 속성만을 포함합니까? –

+0

void __cdecl CString :: Format (_In_ _Printf_format_string_ PCXSTR pszFormat, ...); – surega

+0

http://stackoverflow.com/questions/205529/c-c-passing-variable-number-of-arguments-around –

답변

4

MFC 코드를 통해 약간의 연구와 디버깅을 수행 한 결과, 실제로 정적 코드 분석기 오류 인 "CStringT '를 줄임표로 전달하여 실제로 의심의 여지가있는 사람에게 도움이되기를 바랍니다.

http://www.gimpel.com/html/bugs/bug437.htm

Format 함수는 가변 함수 인, 상기 제 파라미터의 존재 형식 지정에 따라. 첫 번째 매개 변수는 항상 char *입니다.

형식 지정자 (% s, % d, % i ...)를 구문 분석하고 발견 된 형식 지정자의 인덱스를 기반으로 var_arg 배열을 읽고 char * if % s 또는 int로 직접 캐스트합니다. d가 지정됩니다.

따라서 CString이 지정되고 해당 형식 지정자가 % s 인 경우 char *에 대한 직접 형 변환 시도가 CString 객체에서 수행됩니다.

CString a_csName; 
CString a_csAge(_T("20")); 
a_csName.Format(_T("My Age is : %s"),a_csAge); 
wcout<<a_csName; 

내 나이는 내 나이가

052134 그래서이 뒤에 아무런 정보가없는 것입니다 인쇄시겠습니까 20

CString a_csName; 
CString a_csAge(_T("20")); 
a_csName.Format(_T("My Age is : %d"),a_csAge); 
wcout<<a_csName; 

입니다 인쇄겠습니까. 그냥 직접 던지기. 따라서 우리는 POD 또는 사용자 정의 데이터 구조를 전달하여 차이를 만들지 않습니다.

+0

당신은 왜 당신 자신의 질문에 대답하고 있습니까? –

+1

조금 연구를 해보고 이것을 발견했습니다. 그러므로 생각은 그것을 나눌 것입니다. – surega

4

: http://msdn.microsoft.com/en-us/library/aa300688%28v=vs.60%29.aspx

  • 할 수 있습니다 const를 문자 * 및 LPCTSTR 함수 인수 자유롭게 대신 CString을 객체.

아마 CString는 vtable에없는 클래스 및 유형 char* 만 속성. 즉, sizeof(CString) == sizeof(const char*)을 의미하고 CStringconst char*으로 reinterpret_cast하면 const char*을 얻을 수 있습니다.

컴파일러는 구조체를 함수의 가변 부분에 전달하는 것을 허용해서는 안됩니다. 하지만 GCC에서 구조체를 가변 인수로 전달하면 잘못되었으므로 메모리가 복사되고 (즉, 복사 생성자가 사용되지 않음) 경고가 발생합니다. 나는 MSVC가 거기에서 동일하게하고있는 것을 추측한다, 그리고, Format 방법은 단지 주어진 데이터가 const char*이라고 가정하고있다.

다른 예를 들어 보겠습니다. vtable이없는 클래스가 멤버 만 int 인 것으로 가정합니다. variadic 인수에 전달하면 컴파일러는이 객체 내용을 복사합니다.이 내용은 int입니다. 함수를 구현할 때 어떤 식 으로든 int을 받았다는 것을 알게됩니다. 그런 다음 int을 묻는 매개 변수를 쿼리합니다. 메모리 레벨에서 클래스는 int과 다르지 않으므로 "괜찮습니다". 이 함수는 클래스의 int 속성에 액세스합니다.

+0

그렇다면 Format은 const char * 멤버 만있는 구조체를 허용한다는 의미입니까? 아니면 CString 객체에 대한 특별한 처리가 있습니까? – surega

+0

컴파일러가 아닌 코드에서 CString을위한 * 특별한 * 처리가 있습니다. 메모리에있는 객체의 레이아웃은이 효과를 얻기 위해 매우 조심스럽게 관리됩니다. 일반적으로 가변 인수를 통해 클래스 객체를 전달해서는 안됩니다. 만약 당신이 절대적으로 *해야만한다면 * 객체에 포인터를 전달하십시오. –

+0

@surega 더 잘 설명하도록 편집 됨 –

2

최근에이 린트 오류를 ​​해결하고이 스레드를 발견했습니다.

는, 린트 경고를 방지 할 수있는 간단한 방법을 발생 캐스트에 대한 흥미로운 조사가 비록는 다음과 같이 Get.String() CString을 방법을 사용하여 CString을 포인터가 아닌 CString을 구조를 전달하는 것입니다

a_csName.Format(_T("My Age is : %d"), a_csAge.GetString()); 
0

다른 답변을 시작하겠습니다.

struct Value 
{ 
    int nValue; 
    float fOtherValue; 
}; 

int main() 
{ 
    Value theValue; 
    theValue.nValue = 220; 
    theValue.fOtherValue = 3.14f; 

    printf("Value: %d", theValue); 
} 

이 코드는 아무런 문제없이 220을 인쇄합니다. 당신이 theValue 후 두 번째 인수를 전달하지만, 늘 그 : 첫 번째 변수 인수 theValue 이후

printf("Values: %d, %f", theValue, theValue.fOtherValue); 

%d 인수로 지정한 크기에 맞지 않습니다. 따라서 3.14은 표시되지 않을 수도 있습니다. printf, 인수 스택을 밀어 넣는 방법, va_start 등이 작동하는 방식을 설명하지 않겠습니다. 우리가 String 클래스 이런 식으로 디자인 할 때

마찬가지로 :

struct String 
{ 
    char* pData; 

public: 
    String() 
    { 
     pData = new char[40]; 
     strcpy_s(pData, 40, "Sample"); 
    } 
}; 

를 그리고이 방법을 사용

String str; 
printf("%s", str); 

확실히 작동합니다.

하지만 인수 및 호출 스택 손상은 어떻게됩니까? 클래스의 크기 (예 : Value)가 (%d) 형식으로 지정된 데이터 크기 (Value의 경우 4)보다 큰 경우 어떨까요? 음,이 경우 클래스는 주어진 클래스의 크기가 printf 함수가 사용하는 인수 크기와 동일한 지 확인해야합니다.

자세한 내용은 언급하지 않지만 CString은 내부 클래스 CStringData을 사용합니다. 후자의 클래스는 문자열, 길이, 참조 횟수 등을 보유합니다. CString (실제로는 CSimpleStringT)은이 클래스를 사용하지만 CStringData에 의해 관리되는 char/wchar_t의 포인터 만 보유합니다.

크게는 String 클래스로 구현됩니다 (데이터 및 sizeof까지). CString이 크게 구현됩니다.