I'm doing some research about variadic functions and arguments.
I noticed that va_arg is able to cast objects into other objects. For example, when the next argument is a char, but you are using va_arg like it should be an int, it casts the char to an int:
Function call:
AddNumbers(3, 5, 'a', 20);
Function declaration:
int AddNumbers(int count, ...) {
int result;
va_list va;
va_start(va, count);
for(int i = 0; i < count; ++i) {
result += va_arg(va, int);
}
return result;
}
So my question is: what kind of casting does this function use (C-style, dynamic_cast, etc.)?
It has nothing to do with casting. In this case it works because of argument promotion.
When you use a varargs function, integer types smaller than int (like e.g. char) are promoted to int.
That's why it works when passing character literals to the function. If you try some other type, like e.g. a floating point value, then it will no longer work.
As for what the va_arg macro (it's mostly implemented as a macro) does, it is totally implementation dependent. It might not do any casting at all, but use some other form of type punning instead.
It is not exactly casting, because va_arg is a macro, not a function. So the type of va_arg(va, int) is by construction int.
But promotions do occur when calling the variadic function (except for the argument preceding the ellipsis.
So in AddNumbers(3, 5, 'a', 20);, the character 'a' is promoted to an int. You can then either use it as an int as your code does, or convert it back to a char (a conversion not a cast) which is defined because the int value can be represented as a char (by construction)
If I understand your question correctly:
C performs certain "casts" by default when calling a variadic function. GCC calls these default argument promotions. They are:
Signed or unsigned char and short int become signed or unsigned int.
float becomes double.
This isn't really a matter of va_arg doing a cast within AddNumbers; instead, when calling AddNumbers, the caller promotes the arguments to AddNumbers as part of pushing them onto the stack for AddNumbers to use.
Related
I have my function overloaded in code below:
void function(char x, double y) {
cout << "char, double" << endl;
}
void function(int x, int y) {
cout << "int, int" << endl;
}
int main() {
function('a', 'b');
return 0;
}
When i try to compile it says me: "[Warning] ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second"
How does compiler make implicit conversions here so that it's ambiguous which candidate is right?
The literal constants 'a' and 'b' have type char, so there is no exact match. The ambiguity occurs because the first parameter matched the first function, but the preferred conversion of the second is to int, matching the second function.
GCC is very explicit about this, issuing the following diagnostic:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second
GCC seems to be saying, I could resolve this for you, but ISO C++ won't allow it. Type agreement is however important to good code quality and avoidance of errors.
You can coerce the selection by casting:
function( static_cast<int>('a'), static_cast<int>('b') );
or by supplying a function( char, char ) overload.
There are implicit conversions between double, int, and char in C++, so you should use static_cast<int> to convert data from char to int for example.
function( static_cast<int>(c), static_cast<int>(d) );
this will call function( int, int );
In your particular case, you use 'a' and 'b' character literals, which, as I mentioned above, have implicit conversions to int and double, because a char variable represents the ASCII value of the character entered in the assignment operator. Hence, we can initialize an unsigned char variable, or a char in the ways below:
unsigned char a = 97; // the ASCII decimal code for "a"
unsigned char b = 'a'; // translates into 97
Since an unsigned char or char variables is an 8 bits variable, and int is a 32 bit value, they have implicit conversions.
For overload A to be chosen over overload B, the conversions for each argument to A must be as good or better than those for B, and at least one must be better.
In your case, A has (exact match, integral->floating), whereas B has (integral promotion, integral promotion).
Exact match is better than integral promotion, but integral promotion is better than integral->floating conversion. So A has a better conversion in the first argument, and B in the second. So it's ambiguous which one is better overall.
Trying ('a', 'b') for function(char, double) requires no conversion for 'a', and a floating-integral conversion for 'b' (from char to double).
For function(int, int), both 'a' and 'b' require integral promotion (from char to int).
More specifically, if I have the following function pointer type:
typedef void (*callback_type) (intptr_t context, void* buffer, size_t count);
can I safely and without "undefined behavior" do:
callback_type func_ptr = (callback_type)write;
intptr_t context = fd;
func_ptr(context, some_buffer, buffer_size);
?
Where write() is the system call (EDIT: has the signature ssize_t write(int fd, const void *buf, size_t count);, thus takes an int as the first argument), and fd is an int file descriptor. I assume the answer would be the same for C and C++, so I am tagging both.
No
That won't be portable because you are passing a parameter that will be a different size in the common LP64 paradigm.
Also, you aren't dereferencing the function pointer with the correct type, and the results of that are undefined.
Now, as you seem to have concluded, the function pointer will work as expected and the only practical problem is going to be: how will write(2) interpret the intptr_t first parameter?
And the actual run-time problem is that, on LP64, you are passing a 64-bit value to a 32-bit parameter. This might misalign the subsequent parameters. On a system with register parameters it would probably work just fine.
Let's have a look at C standard.
C11 (n1570), § 6.3.2.3 Pointers
A pointer to a function of one type may be converted to a pointer to a
function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to call
a function whose type is not compatible with the referenced type, the
behavior is undefined.
C11 (n1570), § 6.7.6.3 Function declarators (including prototypes)
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.
C11 (n1570), § 6.2.7 Compatible type and composite type
Two types have compatible type if their types are the same.
Conclusion:
void (*) (intptr_t context, void* buffer, size_t count);
cannot be converted to:
void (*) (int context, void* buffer, size_t count);
The problem is not with passing the argument back and forth between functions, since automatic promotion from one integral type to another is done.
The problem is, what if intptr_t is shorter than int, thus not every value of int can be represented by an intptr_t? In such a case, the some of the highest bits in the int will be truncated when converting to intptr_t, so you'll end up write()ing to an invalid file descriptor. Although that should not invoke undefined behavior, it's still erroneous.
Is the following code correct?
char mychar = 200;
printf("%x", mychar);
According to http://www.cplusplus.com/reference/clibrary/cstdio/printf/ %x expects an integer (4 bytes with my compiler) and I only pass 1 byte here. Since printf makes use of varargs, my fear is that this only works because of byte alignment on the stack (i.e. a char always uses 4 bytes when pushed on the stack).
I think it would be better to write:
char mychar = 200;
printf("%x", static_cast<int>(mychar));
Do you think the first code is safe anyway? If not, do you think I could get a different output if I switch to a bigendian architecture?
In your example, the argument is actually of type int. mychar is promoted to int due to the default argument promotions.
(C99, 6.5.2.2p6) "If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions."
and (emphasis mine):
(C99, 6.5.2.2p7) "If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument
promotions are performed on trailing arguments."
Note that technically the x conversion specifier requires an unsigned int argument but int and unsigned int types are guaranteed to have the same representation.
This only works for you because your platform is able to interpret an int (to which your char is promoted) as an unsigned, this is what %x expects. To be sure that this always works you should use and appropriate format specifier, namely %d.
Since it seems that you want to use char as numerical quantity it would be better to use the two alternative types signed char or unsigned char to make your intention clear. char can be a signed or unsigned type on function of your platform. The correct specifier for unsigned char would then be %hhx.
Simply use printf("%hhx", mychar). And please, don't use cplusplus.com as a reference. This question only proves its reputation of containing many errors and leaving out a lot of information.
If you're using C++, then you might want to use streams instead.
You will need to cast characters to integers, otherwise they will be printed as glyphs. Also, signed characters will be sign extended during the cast, so it's better to use unsigned char. For example a char holding 0xFF will print as 0xFFFFFFFF unless casted to unsigned char first.
#include <iostream>
#include <iomanip>
int main(void){
char c = 0xFF;
std::cout << std::hex << std::setw(2) << std::setfill('0');
std::cout << static_cast<int>(static_cast<unsigned char>(c)) << std::endl;
return 0;
}
What is Type Conversion and what is Type Casting?
When should I use each of them?
Detail: Sorry if this is an obvious question; I'm new to C++, coming from a ruby background and being used to to_s and to_i and the like.
Conversion is when a value is, um, converted to a different type. The result is a value of the target type, and there are rules for what output value results from what input (of the source type).
For example:
int i = 3;
unsigned int j;
j = i; // the value of "i" is converted to "unsigned int".
The result is the unsigned int value that is equal to i modulo UINT_MAX+1, and this rule is part of the language. So, in this case the value (in English) is still "3", but it's an unsigned int value of 3, which is subtly different from a signed int value of 3.
Note that conversion happened automatically, we just used a signed int value in a position where an unsigned int value is required, and the language defines what that means without us actually saying that we're converting. That's called an "implicit conversion".
"Casting" is an explicit conversion.
For example:
unsigned int k = (unsigned int)i;
long l = long(i);
unsigned int m = static_cast<unsigned int>(i);
are all casts. Specifically, according to 5.4/2 of the standard, k uses a cast-expression, and according to 5.2.3/1, l uses an equivalent thing (except that I've used a different type). m uses a "type conversion operator" (static_cast), but other parts of the standard refer to those as "casts" too.
User-defined types can define "conversion functions" which provide specific rules for converting your type to another type, and single-arg constructors are used in conversions too:
struct Foo {
int a;
Foo(int b) : a(b) {} // single-arg constructor
Foo(int b, int c) : a(b+c) {} // two-arg constructor
operator float () { return float(a); } // conversion function
};
Foo f(3,4); // two-arg constructor
f = static_cast<Foo>(4); // conversion: single-arg constructor is called
float g = f; // conversion: conversion function is called
Classic casting (something like (Bar)foo in C, used in C++ with reinterpret_cast<>) is when the actual memory contents of a variable are assumed to be a variable of a different type. Type conversion (ie. Boost's lexical_cast<> or other user-defined functions which convert types) is when some logic is performed to actually convert a variable from one type to another, like integer to a string, where some code runs to logically form a string out of a given integer.
There is also static and dynamic casting, which are used in inheritance, for instance, to force usage of a parent's member functions on a child's type (dynamic_cast<>), or vice-versa (static_cast<>). Static casting also allows you to perform the typical "implicit" type conversion that occurs when you do something like:
float f = 3.14;
int i = f; //float converted to int by dropping the fraction
which can be rewritten as:
float f = 3.14;
int i = static_cast<int>(f); //same thing
In C++, any expression has a type. when you use an expression of one type (say type S) in a context where a value of another type is required (say type D), the compiler tries to convert the expression from type S to type D. If such an implicit conversion doesn't exist, this results in an error. The word type cast is not standard but is the same as conversion.
E.G.
void f(int x){}
char c;
f(c); //c is converted from char to int.
The conversions are ranked and you can google for promotions vs. conversions for more details.
There are 5 explicit cast operators in C++ static_cast, const_cast, reinterpret_cast and dynamic_cast, and also the C-style cast
Type conversion is when you actually convert a type in another type, for example a string into an integer and vice-versa, a type casting is when the actual content of the memory isn't changed, but the compiler interpret it in a different way.
Type casting indicates you are treating a block of memory differently.
int i = 10;
int* ip = &i;
char* cp = reinterpret_cast<char*>(ip);
if ( *cp == 10 ) // Here, you are treating memory that was declared
{ // as int to be char.
}
Type conversion indicates that you are converting a value from one type to another.
char c = 'A';
int i = c; // This coverts a char to an int.
// Memory used for c is independent of memory
// used for i.
How do type casting happen without loss of data inside the compiler?
For example:
int i = 10;
UINT k = (UINT) k;
float fl = 10.123;
UINT ufl = (UINT) fl; // data loss here?
char *p = "Stackoverflow Rocks";
unsigned char *up = (unsigned char *) p;
How does the compiler handle this type of typecasting? A low-level example showing the bits would be highly appreciated.
Well, first note that a cast is an explicit request to convert a value of one type to a value of another type. A cast will also always produce a new object, which is a temporary returned by the cast operator. Casting to a reference type, however, will not create a new object. The object referenced by the value is reinterpreted as a reference of a different type.
Now to your question. Note that there are two major types of conversions:
Promotions: This type can be thought of casting from a possibly more narrow type to a wider type. Casting from char to int, short to int, float to double are all promotions.
Conversions: These allow casting from long to int, int to unsigned int and so forth. They can in principle cause loss of information. There are rules for what happens if you assign a -1 to an unsigned typed object for example. In some cases, a wrong conversion can result in undefined behavior. If you assign a double larger than what a float can store to a float, the behavior is not defined.
Let's look at your casts:
int i = 10;
unsigned int k = (unsigned int) i; // :1
float fl = 10.123;
unsigned int ufl = (unsigned int) fl; // :2
char *p = "Stackoverflow Rocks";
unsigned char *up = (unsigned char *) p; // :3
This cast causes a conversion to happen. No loss of data happens, since 10 is guaranteed to be stored by an unsigned int. If the integer were negative, the value would basically wrap around the maximal value of an unsigned int (see 4.7/2).
The value 10.123 is truncated to 10. Here, it does cause lost of information, obviously. As 10 fits into an unsigned int, the behavior is defined.
This actually requires more attention. First, there is a deprecated conversion from a string literal to char*. But let's ignore that here. (see here). More importantly, what does happen if you cast to an unsigned type? Actually, the result of that is unspecified per 5.2.10/7 (note the semantics of that cast is the same as using reinterpret_cast in this case, since that is the only C++ cast being able to do that):
A pointer to an object can be explicitly converted to a pointer to
an object of different type. Except that converting an rvalue of type “pointer to T1” to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
So you are only safe to use the pointer after you cast back to char * again.
The two C-style casts in your example are different kinds of cast. In C++, you'd normally write them
unsigned int uf1 = static_cast<unsigned int>(fl);
and
unsigned char* up = reinterpret_cast<unsigned char*>(p);
The first performs an arithmetic cast, which truncates the floating point number, so there is data loss.
The second makes no changes to data - it just instructs the compiler to treat the pointer as a different type. Care needs to be taken with this kind of cast: it can be very dangerous.
"Type" in C and C++ is a property assigned to variables when they're handled in the compiler. The property doesn't exist at runtime anymore, except for virtual functions/RTTI in C++.
The compiler uses the type of variables to determine a lot of things. For instance, in the assignment of a float to an int, it will know that it needs to convert. Both types are probably 32 bits, but with different meanings. It's likely that the CPU has an instruction, but otherwise the compiler would know to call a conversion function. I.e.
& __stack[4] = float_to_int_bits(& __stack[0])
The conversion from char* to unsigned char* is even simpeler. That is just a different label. At bit level, p and up are identical. The compiler just needs to remember that *p requires sign-extension while *up does not.
Casts mean different things depending on what they are. They can just be renamings of a data type, with no change in the bits represented (most casts between integral types and pointers are like this), or conversions that don't even preserve length (such as between double and int on most compilers). In many cases, the meaning of a cast is simply unspecified, meaning the compiler has to do something reasonable but doesn't have to document exactly what.
A cast doesn't even need to result in a usable value. Something like
char * cp;
float * fp;
cp = malloc(100);
fp = (float *)(cp + 1);
will almost certainly result in a misaligned pointer to float, which will crash the program on some systems if the program attempts to use it.