Reason why int(*g)(int) into int(*h)(char) causes error? - c++

I am studying programming language principles and I have a question with C and C++.
int (*f)(int);
int (*g)(int);
int (*h)(char);
f = g; // ok
h = g; // warning in C, error in C++
Assigning g into f (f = g) will not cause an error in C or C++, but assigning g into h (h = g) would generate a compiler warning in C and compile error in C++.
I heard that the char type is usually auto-casted into int in C++, so I thought this would not cause an error.
Can someone explain this to me?

Assigning g into f (f = g) will not cause an error in C/C++, but assigning g into h (h = g) would generate a compiler warning in C and compile error in C++.
This is incorrect. A program that attempts to do h = g is an invalid program, be it C or C++. However the C standard explicitly mentions that a C compiler is allowed to successfully compile an invalid program, provided that it issues a diagnostic message for every violation of certain rules. You got your warning and then the C compiler proceeded anyhow.
In fact, C++ standard contains a very similar wording:
If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this document as “conditionally-supported” when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.
[...]
A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this document.
Having done so, however, they can compile and execute such programs.
But customarily C++ compilers are by default more strict when it comes to diagnosable violations and the compilation will fail by default whereas the C compiler from the same vendor would successfully compile such a translation unit.
Note that both C and C++ has a provision that you can do the conversion with a cast, i.e. h = (int (*)(char))g; but you again must not call a function through h without casting it back to int (*)(int) first!

For two function types to be compatible, the returns types must match and the number and types of the arguments must match. The conversion rules that apply between integer types do not apply to arguments of function types.
Section 6.7.6.3p15 of the C standard states the following:
For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)
The types int and char are not compatible with each other, therefore a function with one int parameter and another with one char parameter are not compatible with each other, making the assignment in your example invalid.
C compilers will typically warn when attempting a conversion between incompatible pointer types. Attempting to defererence h in your example by calling the function will invoke undefined behavior.

When you define a pointer to a function, you essentially define a new variable type.
So in your example, f and g are the same type, because they are defined identically, but h is another type, because it is defined differently.
While both C and C++ compilers know how to convert between char and int types, as those are built in to the language, they don't know how to convert between g and h types, because you defined those.
The fact that char is part of g definition does not help here, because the compiler has no right to alter the internals of your definitions.
Consider the kind of bugs this could cause:
If you use a calling convention where all arguments are put on the stack, sending a char to a function that expects int would cause it to get a wrong value, as it will be reading extra bytes from the stack that are not part of the sent value.

You might also wonder why those function pointers are not implicitly-convertible into each other. Consider the following function definition:
void f(void(*f)(char))
{
f('A');
}
A compiler now needs to generate a machine code for this function. In my case, it was:
mov rax, rdi
mov edi, 65
jmp rax
This machine code would generally not work if, as an argument of f, would be passed a pointer to a function that has a parameter of a different type. Here, the argument to f is passed through the edi register. By coincidence, that would work also for a function that has a parameter of type int with my implementation. But this is purely an implementation issue and the standard rules may not be driven by it.
For illustration, if I would pass, as an argument of f, a pointer to the function that has a parameter of type long, this would stop working, since then the argument would not be passed to f through the rdi register (as this function would expect).

Related

Why is 'void' used and not a specific data type as argument for a function in C++ using a class object array? [duplicate]

Consider these two function definitions:
void foo() { }
void foo(void) { }
Is there any difference between these two? If not, why is the void argument there? Aesthetic reasons?
In C:
void foo() means "a function foo taking an unspecified number of arguments of unspecified type"
void foo(void) means "a function foo taking no arguments"
In C++:
void foo() means "a function foo taking no arguments"
void foo(void) means "a function foo taking no arguments"
By writing foo(void), therefore, we achieve the same interpretation across both languages and make our headers multilingual (though we usually need to do some more things to the headers to make them truly cross-language; namely, wrap them in an extern "C" if we're compiling C++).
I realize your question pertains to C++, but when it comes to C the answer can be found in K&R, pages 72-73:
Furthermore, if a function declaration does not include arguments, as
in
double atof();
that too is taken to mean that nothing is to be assumed about the
arguments of atof; all parameter checking is turned off. This special
meaning of the empty argument list is intended to permit older C
programs to compile with new compilers. But it's a bad idea to use it
with new programs. If the function takes arguments, declare them; if
it takes no arguments, use void.
C++11 N3337 standard draft
There is no difference.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
Annex C "Compatibility" C.1.7 Clause 8: declarators says:
8.3.5 Change: In C ++ , a function declared with an empty parameter list takes no arguments. In C, an empty
parameter list means that the number and type of the function arguments are unknown.
Example:
int f();
// means int f(void) in C ++
// int f( unknown ) in C
Rationale: This is to avoid erroneous function calls (i.e., function calls with the wrong number or type of
arguments).
Effect on original feature: Change to semantics of well-defined feature. This feature was marked as “obsolescent” in C.
8.5.3 functions says:
4. The parameter-declaration-clause determines the arguments that can be specified, and their processing, when
the function is called. [...] If the parameter-declaration-clause is empty, the function
takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
C99
As mentioned by C++11, int f() specifies nothing about the arguments, and is obsolescent.
It can either lead to working code or UB.
I have interpreted the C99 standard in detail at: https://stackoverflow.com/a/36292431/895245
In C, you use a void in an empty function reference so that the compiler has a prototype, and that prototype has "no arguments". In C++, you don't have to tell the compiler that you have a prototype because you can't leave out the prototype.

What is a formal parameter?

When compiling in C++ I often end up with error messages dealing with "formal parameters", such as
error C2719: 'b': formal parameter with __declspec(align('16')) won't be aligned
I do understand the error, and the fact that b is a parameter of a function I am defining.
However, what does it mean that a parameter is formal? Can there be informal parameters as well?
I do notice that the term "formal parameter" appears in other languages as well, so I presume it is a more generic term not necessarily specific to C-family of languages? Are informal parameters supported by some subset of languages?
Upon seeing the answers, one final question: Where those names formal parameter and actual parameter origin from? Does it origin from the C standard, or is it an effect of calling it as such in some abstract language calculus?
There are formal and actual parameters:
void foo(int arg); //arg is a formal parameter
int main()
{
int val = 1;
foo(val); //val is an actual parameter
}
From C++ Standard:
1.3.1 formal parameter (parameter)
an object or reference declared as part of a function declaration or
definition, or in the catch clause of an exception handler, that
acquires a value on entry to the function or handler; an identifier
from the comma-separated list bounded by the parentheses immediately
following the macro name in a function-like macro definition; or a
template-parameter. Parameters are also known as formal arguments or
formal parameters.
1.3.10 actual parameter (argument)
an expression in the comma-separated list bounded by the parentheses
in a function call expression, a sequence of preprocessing tokens in
the comma-separated list bounded by the parentheses in a function-like
macro invocation, the operand of throw, or an expression, type-id or
template-name in the comma-separated list bounded by the angle
brackets in a template instantiation. Also known as an actual argument
or actual parameter.
Formal parameters are the parameters known at the function definition. The actual parameters are what you actually (hence the name) pass to the function when you call it.
void foo( int a ); // a is a formal parameter
foo(10); // 10 is the actual parameter
It's a matter of being a little pedantic over terminology, but quite useful: The formal parameters are what you just think of function parameters:
int foo(bool a, float b);
Here a and b are formal parameters. The point is that in the function body, you're referring to those parameters "formally" without actually knowing their value. It is only when you actual evaluate a function call expression that the formal function parameters are bound to the function call arguments:
int result = foo(false, 1.5);
In this call expression, the value false of the first argument is bound to the formal parameter a, and similarly for the second argument.
The distinction between parameters and arguments is maybe more important to language designers and comiler writers, but as an example in C++, it can be very helpful to get your head around this when you're trying to follow the rules for template argument deduction.

`f(void)` meaning no parameters in C++11 or C?

In C++11 the following function declaration:
int f(void);
means the same as:
int f();
A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
I get the (perhaps false) impression this is an old feature, perhaps inherited from C?
Does anyone know the history or rationale behind this way to declare a function with no parameters?
In C++ they both mean the same thing.
In C f(void) is different from f(), becuse f() means "unspecified parameters" - you can legally pass anything (whether the function at receiving the data is happy about that or not is another matter).
In C++ both are the same thing.
In C, f() means that we don't know how many parameters the function takes at this point. It is unspecified parameters. And f(void) means that this function does not take any parameters.
From the C standard :
6.7.6.3 Function declarators (including prototypes)
6/ A parameter type list specifies the types of, and may declare identifiers for, the
parameters of the function.
10/ The special case of an unnamed parameter of type void as the only item in the list
specifies that the function has no parameters.
14/ An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
And like you said, in the C++ standard :
8.3.5 Functions [dcl.fct]
4/ The parameter-declaration-clause determines the arguments that can be specified, and their processing, when the function is called. [ Note: *the parameter-declaration-clause* is used to convert the arguments specified on the function call; see 5.2.2. —end note ] If the parameter-declaration-clause is empty, the function takes no arguments. A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
This comes to C++ from C. In C f() means unknown number and type of parameters. So in C for no parameters there is f( void ).
In C++ it's redundant: f() and f( void ) mean same thing - a function that has no parameters.
From "A History of C++" (1979− 1991 by Bjarne Stroustrup) at p11:
C with Classes introduced the notation f(void) for a function f that
takes no arguments as a contrast to f() that in C declares a function
that can take any number of arguments of any type without any type
check.
It says later, however, that soon the empty function declarator was given its obvious meaning and the new construct - kinda rendered obsolete for the time. I guess nobody has bothered removing it after (or maybe there had been already some C++ code written with it that have needed support).
In C:
This construct however rendered important role as of the standardization of the C language where function prototyping was borrowed directly from C++. In this case f(void) was useful in supporting existing C code (in which the notion f() was already reserved as to indicate a function taking unspecified number of arguments).
Before that the C language hadn't been able to attach specific types to each parameter but only functions with unspecified number of arguments and with unspecified types were declarable using the f() form.
In C++, there is no difference. However, this is inherited from C, where int f() mean "function which can take any number of arguments of any types" and int f(void); specifies functions that takes no arguments.
Edit As Angew pointed out, in C, f() means "function whose parameters are unknown at this point." It does not mean it can take any number of arguments - close to that would be f(T arg, ...), where arg is at least one named parameter before ..., which accepts at least one argument, arg (as pointed by #hvd).

How does this C++ template class code work?

I am trying to port Google Test (gtest) code to VxWorks 5.5. The serious drawback is that development environment Tornado 2.2 uses ancient GCC compiler version 2.96.
While analyzing the code I've located part of the code in gtest.h I do not understand! How this C++ template class is functioning?
// ImplicitlyConvertible<From, To>::value is a compile-time bool
// constant that's true iff type From can be implicitly converted to
// type To.
template <typename From, typename To>
class ImplicitlyConvertible {
private:
// We need the following helper functions only for their types.
// They have no implementations.
// MakeFrom() is an expression whose type is From. We cannot simply
// use From(), as the type From may not have a public default
// constructor.
static From MakeFrom();
// These two functions are overloaded. Given an expression
// Helper(x), the compiler will pick the first version if x can be
// implicitly converted to type To; otherwise it will pick the
// second version.
//
// The first version returns a value of size 1, and the second
// version returns a value of size 2. Therefore, by checking the
// size of Helper(x), which can be done at compile time, we can tell
// which version of Helper() is used, and hence whether x can be
// implicitly converted to type To.
static char Helper(To);
static char (&Helper(...))[2]; // NOLINT
// We have to put the 'public' section after the 'private' section,
// or MSVC refuses to compile the code.
public:
// MSVC warns about implicitly converting from double to int for
// possible loss of data, so we need to temporarily disable the
// warning.
#ifdef _MSC_VER
# pragma warning(push) // Saves the current warning state.
# pragma warning(disable:4244) // Temporarily disables warning 4244.
static const bool value =
sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
# pragma warning(pop) // Restores the warning state.
#elif defined(__BORLANDC__)
// C++Builder cannot use member overload resolution during template
// instantiation. The simplest workaround is to use its C++0x type traits
// functions (C++Builder 2009 and above only).
static const bool value = __is_convertible(From, To);
#else
static const bool value =
sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
#endif // _MSV_VER
};
When object of this class is created, boolean variable with the name value should contain the answer if template type From is implicitly convertible to template type To. To get the answer, two private functions are used, MakeFrom() and Helper(). But these two functions are only declared here, and I cannot find definition for neither of them. If nothing else, this implementation should not link.
Neither do I understand the syntax of the following
static char (&Helper(...))[2];
Of course, this code compiles just fine (under Microsoft Visual C++ 7.1 or newer or GCC 3.4 or newer) and guys at Google know exactly what they are doing.
Please enlighten me! Not understanding this code will make me go crazy! :)
This is a standard trick with template programming.
Note that the comments say "by checking the size of Helper(x)": this underscores that the only thing the code does with Helper is evaluate sizeof(Helper(x)) for some x. The sizeof operator does not actually evaluate its argument (it doesn't need to; it only needs to find out how large it is, which is possible using only information available at compile time) and this is why there is no linker error (Helper is never really called).
The syntax that gives you trouble means that Helper is a function that accepts any number and type of parameters and returns a reference to a char[2]. To write a signature for this type of function (a variadic function) one needs to use ellipsis (...) as the specification for the last argument.
Variadic functions are a feature inherited from C that should generally be avoided and that wreaks havoc when used with class types, but in this case it does not matter because -- as mentioned earlier -- Helper will not be actually called.
The class ties this all together by allowing you to use the syntax
ImplicitlyConvertible<From, To>::value
To produce value, the code "fakes" calling Helper and passing it an instance of From as an argument¹. It relies on the compiler's overload resolution to determine if the overload that takes a To would be called in this scenario; if so, the return value of that overload is char which has a guaranteed size of 1 and value ends up being true. Otherwise the variadic overload (which can take any type of argument) is selected, which returns a char[2]. This has a size greater than 1, so value ends up false.
¹ Note that here the "sizeof does not actually evaluate the expression" trick is used again: how do you tell the compiler that the argument to Helper is an instance of From? You could use From(), but then From would need to have a default public constructor for the code to compile. So you just tell the compiler "I have a function MakeFrom that returns a From" -- the function will not be actually called.

Is there a difference between foo(void) and foo() in C++ or C?

Consider these two function definitions:
void foo() { }
void foo(void) { }
Is there any difference between these two? If not, why is the void argument there? Aesthetic reasons?
In C:
void foo() means "a function foo taking an unspecified number of arguments of unspecified type"
void foo(void) means "a function foo taking no arguments"
In C++:
void foo() means "a function foo taking no arguments"
void foo(void) means "a function foo taking no arguments"
By writing foo(void), therefore, we achieve the same interpretation across both languages and make our headers multilingual (though we usually need to do some more things to the headers to make them truly cross-language; namely, wrap them in an extern "C" if we're compiling C++).
I realize your question pertains to C++, but when it comes to C the answer can be found in K&R, pages 72-73:
Furthermore, if a function declaration does not include arguments, as
in
double atof();
that too is taken to mean that nothing is to be assumed about the
arguments of atof; all parameter checking is turned off. This special
meaning of the empty argument list is intended to permit older C
programs to compile with new compilers. But it's a bad idea to use it
with new programs. If the function takes arguments, declare them; if
it takes no arguments, use void.
C++11 N3337 standard draft
There is no difference.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
Annex C "Compatibility" C.1.7 Clause 8: declarators says:
8.3.5 Change: In C ++ , a function declared with an empty parameter list takes no arguments. In C, an empty
parameter list means that the number and type of the function arguments are unknown.
Example:
int f();
// means int f(void) in C ++
// int f( unknown ) in C
Rationale: This is to avoid erroneous function calls (i.e., function calls with the wrong number or type of
arguments).
Effect on original feature: Change to semantics of well-defined feature. This feature was marked as “obsolescent” in C.
8.5.3 functions says:
4. The parameter-declaration-clause determines the arguments that can be specified, and their processing, when
the function is called. [...] If the parameter-declaration-clause is empty, the function
takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
C99
As mentioned by C++11, int f() specifies nothing about the arguments, and is obsolescent.
It can either lead to working code or UB.
I have interpreted the C99 standard in detail at: https://stackoverflow.com/a/36292431/895245
In C, you use a void in an empty function reference so that the compiler has a prototype, and that prototype has "no arguments". In C++, you don't have to tell the compiler that you have a prototype because you can't leave out the prototype.