V510. The 'Foo' function is not expected to receive class-type variable as 'N' actual argument

15.12.2011

There are functions in whose description it is impossible to specify the number and types of all the acceptable parameters. In this case, the list of formal arguments ends with the ellipsis (...) that means: "and perhaps some more arguments". Here is an example of an ellipsis function: "int printf(const char* ...);". Only POD-types can serve as actual arguments for ellipsis.

POD is an abbreviation for "Plain Old Data", i.e. "Plain data in C style". The following types and structures refer to POD-types:

  • all the built-in arithmetic types (including wchar_t and bool);
  • types defined with the enum key word;
  • pointers;
  • POD-structures (struct or class) and POD-unions that meet the following requirements:
    • do not contain user constructors, destructor or copying assignment operator;
    • do not have base classes;
    • do not contain virtual functions;
    • do not contain protected or private non-static data members;
    • do not contain non-static data members of non-POD-types (or arrays of such types) and references.

If a class object is passed to an ellipsis function, this almost always indicates an error in program. The V510 rule helps detect incorrect code of the following kind:

wchar_t buf[100];
std::wstring ws(L"12345");
swprintf(buf, L"%s", ws);

The object's contents are saved into the stack instead of the pointer to the string. This code will cause generating "abracadabra" in the buffer or a program crash.

The correct version of the code must look this way:

wchar_t buf[100];
std::wstring ws(L"12345");
swprintf(buf, L"%s", ws.c_str());

Since you might pass anything you like into functions with a variable number of arguments, almost all the books on C++ programming do not recommend using them. They suggest employing safe mechanisms instead, for instance, boost::format.

Note one specific thing about using the CString class from the MFC library

We must see an error similar to the one mentioned above in the following code:

CString s;
CString arg(L"OK");
s.Format(L"Test CString: %s\n", arg);

The correct version of the code must look in the following way:

s.Format(L"Test CString: %s\n", arg.GetString());

Or, as MSDN suggests [1], you may use the explicit cast operator LPCTSTR implemented in the CString class to get a pointer to the string. Here is a sample of correct code from MSDN:

CString kindOfFruit = "bananas";
int howmany = 25;
printf("You have %d %s\n", howmany, (LPCTSTR)kindOfFruit);

However, the first version "s.Format(L"Test CString: %s\n", arg);" is actually correct as well like the others. This topic is discussed in detail in the article "Big Brother helps you" [2].

The MFC developers implemented the CString class in a special way so that you could pass it into functions of the printf and Format types. It is done rather intricately and if you want to make it out, study implementation of the CStringT class in the source codes and also read a detailed discussion "Pass CString to printf?" [3].

So, the analyzer makes an exception for the CStringT type and considers the following code correct:

CString s;
CString arg(L"OK");
s.Format(L"Test CString: %s\n", arg);

Related materials

You can look at examples of errors from real projects which were detected by this diagnostic message.