передача объекта в функцию var arg

Как переменная аргументная функция переносит объект в структуру / класс?
Например :

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

Вот CString::Format является функцией аргумента переменной в стиле printf, которая принимает это CString объект. Как это возможно?

2

Решение

После небольшого исследования и отладки с помощью кода MFC, найденного ниже, надеюсь, он поможет любому, кто столкнется с когда-либо известной ошибкой статического анализатора кода «Передача структуры ‘CStringT’ многоточию”, которая на самом деле является источником моих сомнений.

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

Функция форматирования, являющаяся переменной функцией, зависит от спецификатора формата, присутствующего в первом параметре. Первый параметр — это всегда символ *.

Он анализирует спецификатор формата (% s,% d,% i…) и считывает массив var_arg на основе индекса найденного спецификатора формата и выполняет прямое приведение к char *, если% s или int, если указан% d.

Таким образом, если указана CString, а соответствующий спецификатор формата равен% s, то для объекта CString делается прямая попытка приведения к char *.

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

Напечатал бы мой возраст 20

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

Напечатал бы мой возраст 052134

Так что за этим нет разума. Просто прямой актерский состав. Следовательно, мы передаем POD или пользовательскую структуру данных, это не имеет значения.

4

Другие решения

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

  • Вы можете свободно заменять объекты CString аргументами функций const char * и LPCTSTR.

Наверное CString класс без vtable и только с атрибутом типа char*, Это означает, что sizeof(CString) == sizeof(const char*) и что если вы reinterpret_cast CString к const char* ты получишь работу const char*,

Компилятор не должен принимать передачу структуры переменной части функции. Но если я не ошибаюсь, в GCC, когда вы передаете структуру как переменный аргумент, она копируется в память (т.е. не используется конструктор копирования) и выдается предупреждение. Я думаю, что MSVC делает то же самое там, а затем, Format Метод просто предполагает, что данные являются const char*,

Позвольте мне привести альтернативный пример. Предположим, у вас есть класс без vtable, в котором только члены являются int. Если вы передадите его переменному аргументу, компилятор скопирует содержимое этого объекта, которое является только int. Что касается реализации функции, вы (каким-то образом) знаете, что вы получили int, Затем вы запрашиваете параметр, запрашивая int, Так как на уровне памяти ваш класс ничем не отличается от intвсе будет работать «хорошо». Функция получит доступ к int атрибут класса.

4

Мне недавно пришлось очистить эту ошибку Lint и наткнулся на эту тему.

Хотя это интересное исследование происходящего приведения, самый простой способ избежать предупреждения Lint — передать указатель CString, а не структуру CString с помощью метода CString. Get.String() как в следующем

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

Позвольте мне начать отвечать на этот вопрос по-другому.

struct Value
{
int nValue;
float fOtherValue;
};

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

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

Этот код напечатает 220 без проблем. Но если вы передадите второй аргумент после theValueне будет:

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

Так как первый переменный аргумент theValue не соответствует размеру, указанному %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) больше размера данных (4 для Value) как указано форматом (%d). Ну, в этом случае, разработанный класс должен гарантировать, что размер данного класса совпадает с размером аргумента, используемого printf функция.

Я не буду упоминать детали об этом, но CString использует внутренний класс CStringData, Последний класс содержит строку, длину, количество ссылок и т. Д. CString (на самом деле CSimpleStringT) использует этот класс, но содержит только указатель char/wchar_t, управляемый CStringData,

Во многом, CString реализуется как String упомянутый класс (насколько данные и sizeof идет).

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector