Typecasting Pointers in C [duplicate] - c

This question already has answers here:
Assigning Float Pointers in C [closed]
(3 answers)
Closed 9 years ago.
I'm new to C, and I'm writing a very basic function that takes an integer pointer as a parameter. Inside the function, a float pointer must be created. This function must assign the value of the integer pointer to the float and then return the float. Here's my code at the moment:
float * function(const int *x)
{
float *p = (float*)x;
return p;
}
But this results in an error that reads as such when run: "free(): invalid pointer: 0x00007fffc0e6b734". Suffice it to say, I'm very confused. Any insights you can offer would be much appreciated!

Being new to C, are you familiar with the scope of variables? (Part of) the short version of variable scope is that if you don't do a little something extra, a variable created in a function only exists inside that function. Why that's important to you: if you return a pointer to a variable that you created inside a function (without doing that little something extra) that pointer will point to an area of memory that may or may not contain the value that you assigned to it. One way to do what you want is this:
float *makefloat(int *x) {
// static keyword tells C to keep this variable after function exits
static float f;
// the next statement working from right to left does the following
// get value of pointer to int (x) by dereferencing: *x
// change that int value to a float with a cast: (float)
// assign that value to the static float we created: f =
f = (float) *x;
// make pointer to float from static variable: &f
return &f;
}
In general I seem to see more functions that accept a pointer to the variable that is to be modified, then in that function the new value is created and assigned to the area in memory referenced by the pointer. Because that area of memory exists outside of the scope of the function, there is no need to worry as much about scope and static variables. Another cool thing about static variables is that the next time the function is called, the static variable has the same value it did when the function last exited. Explained on Wikipedia.
Good explanation of * and &: Pointers in C: when to use the ampersand and the asterisk

Your function only performs a pointer conversion. A function call of the form
q = function(p); /* p is a "const int *" pointer,
q is assignment comaptible with "float *". */
can be replaced by the expression:
q = (float *) p;
by itself, this doesn't do any harm. The problem is elsewhere in your program.
Note that most type punning, like accessing an object of type int using an expression of type float via pointers, is undefined behavior in the C language. This isn't going on in the example code, but things are headed in that direction; the pointer is probably being prepared for carrying out type punning.
Consider that int and float don't necessarily even have the same size; and that is not the only consideration. In code like this:
int i = 42;
/* now treat i as a float and modify it sneakily */
*((float *) &i) = 3.14;
printf("i = %d\n", i);
the output of the printf can still be 42. The optimizing compiler can put i into a machine register, whereas the sneaky assignment might be performed on the memory location that serves as the "backing storage" for i, and so i appears unchanged since the printf call uses the register-cached copies. The compiler is not required to consider that a modification of an object designated by the type float might affect the value of an object of type i (even if they otherwise have the same size, so there is no collateral damage done by the assignment, like overwriting other objects).
In the real world, sometimes it is necessary to write a code that manipulates floating-point objects as if they were integers: typically unsigned int integers, to gain access to the bitwise representation of the float. When this is done, you have to use unions, or perhaps compiler-specific features, like GCC's -fno-strict-aliasing option which causes the compiler to optimize more cautiously in the face of type punning. in that kind of code, you make sure that the assumptions are all warranted about the sizes of types and such, with #ifdef-s for different platforms, perhaps based on values pulled from running configured scripts to detect platform features.
Needless to say, this is not a good way to be learning C at a beginner level.

Related

Passing float to a function with int argument (that is not declared beforehand)

I have read Garbage value when passed float values to the function accepting integer parameters answers. My question goes a bit deeper. I could have also asked there had I more than 50 reputation point. I am adding my code for more clarification:
#include <stdio.h>
#include <string.h>
void p2(unsigned int tmp)
{
printf("From p2: \n");
printf("tmp = %d ,In hex tmp = %x\n", tmp, tmp);
}
int main()
{
float fvar = 45.65;
p1(fvar);
p2(fvar);
printf("From main:\n");
printf("sizeof(int) = %lu, sizeof(float) = %lu\n", sizeof(int),
sizeof(float));
unsigned int ui;
memcpy(&ui, &fvar, sizeof(fvar));
printf("fvar = %x\n", ui);
return 0;
}
void p1(unsigned int tmp)
{
printf("From p1: \n");
printf("tmp = %d ,In hex tmp = %x\n", tmp, tmp);
}
The output is:
From p1:
tmp = 1 ,In hex tmp = 1
From p2:
tmp = 45 ,In hex tmp = 2d
From main:
sizeof(int) = 4, sizeof(float) = 4
fvar = 4236999a8
Passing a float value to a function that is declared beforehand (i.e. p2) with int arguments gives the correct result. When trying the same with a function that is not declared beforehand (i.e. p1) gives incorrect values. And I know the reason that compiler won't assume any type or arity of arguments for the function not declared before handed. That's why float value does not get typecasted to int in the case of p2.
My confusion is, in the case of p2, how exactly does float value get copied to local int variable tmp.
If it is 'bit by bit copy' than reading those locations should yield something (except 1) in hex at least (if not in integer). But that does not sound the case as output shows. I know that float representation is different.
And how p2 may read registers/stack locations that floats weren't copied to? as simonc suggested in the linked question?
I have included the size of int and float both and my compiler is gcc if that helps.
The C programming language is essentially a single-scan language - a compiler doesn't need to reread the code but it can assemble it line by line, retaining information only on how identifiers were declared.
The C89 standard had the concept of implicit declaration. In absence of a declaration, the function p1 is declared implicitly as int p1(); i.e. a function that returns an int and takes unspecified arguments that go through default argument promotions. When you call such a function giving it a float as an argument, the float argument is promoted to a double, as called for by default argument promotions. It would be fine if the function was int p1(double arg); but the expected argument type is unsigned int, and the return value is not compatible either (void vs int). This mismatch will cause the program to have undefined behaviour - there is no point in reasoning what is happening then. However, there are many old C programs that would fail to compile, if the compilers wouldn't support the archaic implicit declarations - thus you just need to consider all these warnings as errors.
Notice that if you change the return value of p1 into an int, you will get less warnings:
% gcc implicit.c
implicit.c:14:5: warning: implicit declaration of function ‘p1’ [-Wimplicit-function-declaration]
p1(fvar);
^~
But the observed behaviour on my compiler would be mostly the same.
Thus the presence of mere warning: implicit declaration of function ‘x’ is quite likely a serious error in newly written code.
Were the function declared before its use, as is case with p2, then the compiler knows that it expects an unsigned long as the argument, and returns void, and therefore it would know to generate correct conversion code from float to unsigned long for the argument.
The C99 and C11 do not allow implicit function declarations in strictly-conforming programs - but they also do not require a conforming compiler to reject them either. C11 says:
An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).
and a footnote noting that
Thus, an undeclared identifier is a violation of the syntax.
However, it doesn't require a compiler to reject them.
This,
void p1(unsigned int tmp);
would be implicitly declared as
int p1();
by the compiler.
Although the compiler does not throw an error, it should be considered one as you can read in the linked post.
In any event, this is undefined behavior and you can't expect a predictable output.
In binary level, float and int don't look alike at all.
When trying to copy a float into a int, there's an implicit conversion, that's why when you call a function that takes int as argument but you provide a float you get the integer part of it, but in the final test you get to see how ugly it really look like. That's no garbage, that's how a float looks like in memory if you'd print it in hexadecimal. See IEEE 754 for details.
The issue with p1() however is that you are trying to call a function that has not been declared, so it's automatically declared as int p1(). Even though you later define it as void p1(unsigned int tmp), it has already been declared as int p1() (not taking any parameters) so it doesn't work (behavior is undefined). I'm pretty sure the compiler is screaming with warnings and errors about that, those errors aren't meant to be ignored.
Notice there's a big difference between declaring and defining a function. It is perfectly legal to define a function later, the way you are doing, but if you want it to work properly it has to be declared before any attempt to use it.
Example:
// declare functions
void p1(unsigned int tmp);
void p2(unsigned int tmp);
// use functions
int main()
{
p1(1);
p2(1);
}
// define functions
void p1(unsigned int tmp)
{
// do stuff
}
void p2(unsigned int tmp)
{
// do stuff
}

C gives different output based on optimization level (new example)

Based on this very good blog post, The Strict Aliasing Situation is Pretty Bad, I've placed the piece of code online for you to test it:
http://cpp.sh/9kht (output changes between -O0 and -O2)
#include <stdio.h>
long foo(int *x, long *y) {
*x = 0;
*y = 1;
return *x;
}
int main(void) {
long l;
printf("%ld\n", foo((int *)&l, &l));
}
Is there some sort of undefined behaviour here?
What is going on internally when we choose the -O2 level?
Yes, this program has undefined behavior, because of the type-based aliasing rules, which can be summarized as "you cannot access a memory location declared with type A through a pointer of type B, except when B is a pointer to a character type (e.g. unsigned char *)." This is an approximation, but it is close enough for most purposes. Note that when A is a pointer to a character type, B may not be something else—yes, this means the common idiom of accessing a byte buffer "four at a time" through an uint32_t* is undefined behavior (the blog post also touches on this).
The compiler assumes, when compiling foo, that x and y may not point to the same object. From this, it infers that the write through *y cannot change the value of *x, and it can just return the known value of *x, 0, without re-reading it from memory. It only does this when optimization is turned on because keeping track of what each pointer can and cannot point to is expensive (so the compilation is slower).
Note that this is a "demons fly out of your nose" situation: the compiler is entitled to make the generated code for foo start with
cmp rx, ry
beq __crash_the_program
...
(and a tool like UBSan might do just that)
Said another way, the code (int *)&l says treat the pointer as a pointer to an int. It does not convert anything. So, the (int *) tells the compiler to allow you to pass a long* to a function expecting an int*. You are lying to it. Inside, foo expects x to be a pointer to an int, but it isn't. The memory layout is not what it should be. Results are, as you see, unpredictable.
On another note, I wouldn't ever use l (ell) as a variable name. It is too easily confused with 1 (one). For example, what is this?
int x = l;

Are pointers considered a method of calling by reference in C?

In my University's C programming class, the professor and subsequent book written by her uses the term call or pass by reference when referring to pointers in C.
An example of what is considered a 'call by reference function' by my professor:
int sum(int *a, int *b);
An example of what is considered a 'call by value function' by my professor:
int sum(int a, int b);
I've read C doesn't support call by reference. To my understanding, pointers pass by value.
Basically, is it incorrect to say pointers are C's way of passing by reference? Would it be more correct to say you cannot pass by reference in C but can use pointers as an alternative?
Update 11/11/15
From the way my question originated, I believe a debate of terminology has stemmed and in fact I'm seeing two specific distinctions.
pass-by-reference (the term used mainly today): The specific term as used in languages like C++
pass-by-reference (the term used by my professor as a paradigm to explain pointers): The general term used before languages like C++ were developed and thus before the term was rewritten
After reading #Haris' updated answer it makes sense why this isn't so black and white.
you cannot pass by reference in C but can use pointers as an alternative
Yup, thats correct.
To elaborate a little more. Whatever you pass as an argument to c functions, it is passed by values only. Whether it be a variable's value or the variable address.
What makes the difference is what you are sending.
When we pass-by-value we are passing the value of the variable to a function. When we pass-by-reference we are passing an alias of the variable to a function. C can pass a pointer into a function but that is still pass-by-value. It is copying the value of the pointer, the address, into the function.
If you are sending the value of a variable, then only the value will be received by the function, and changing that won't effect the original value.
If you are sending the address of a variable, then also only the value(the address in this case) is sent, but since you have the address of a variable it can be used to change the original value.
As an example, we can see some C++ code to understand the real difference between call-by-value and call-by-reference. Taken from this website.
// Program to sort two numbers using call by reference.
// Smallest number is output first.
#include <iostream>
using namespace std;
// Function prototype for call by reference
void swap(float &x, float &y);
int main()
{
float a, b;
cout << "Enter 2 numbers: " << endl;
cin >> a >> b;
if(a>b)
swap(a,b); // This looks just like a call-by-value, but in fact
// it's a call by reference (because of the "&" in the
// function prototype
// Variable a contains value of smallest number
cout << "Sorted numbers: ";
cout << a << " " << b << endl;
return 0;
}
// A function definition for call by reference
// The variables x and y will have their values changed.
void swap(float &x, float &y)
// Swaps x and y data of calling function
{
float temp;
temp = x;
x = y;
y = temp;
}
In this C++ example, reference variable(which is not present in C) is being used. To quote this website,
"A reference is an alias, or an alternate name to an existing variable...",
and
"The main use of references is acting as function formal parameters to support pass-by-reference..."
This is different then the use of pointers as function parameters because,
"A pointer variable (or pointer in short) is basically the same as the other variables, which can store a piece of data. Unlike normal variable which stores a value (such as an int, a double, a char), a pointer stores a memory address."
So, essentially when one is sending address and receiving through pointers, one is sending the value only, but when one is sending/receiving a reference variable, one is sending an alias, or a reference.
**UPDATE : 11 November, 2015**
There has been a long debate in the C Chatroom, and after reading comments and answers to this question, i have realized that there can be another way to look at this question, another perspective that is.
Lets look at some simple C code
int i;
int *p = &i;
*p = 123;
In this scenario, one can use the terminology that, p's value is a reference to i. So, if that is the case, then if we send the same pointer (int* p) to a function, one can argue that, since i's reference is sent to the function, and thus this can be called pass-by-reference.
So, its a matter of terminology and way of looking at the scenario.
I would not completely disagree with that argument. But for a person who completely follows the book and rules, this would be wrong.
NOTE: Update inspired by this chat.
Reference is an overloaded term here; in general, a reference is simply a way to refer to something. A pointer refers to the object pointed to, and passing (by value) a pointer to an object is the standard way to pass by reference in C.
C++ introduced reference types as a better way to express references, and introduces an ambiguity into technical English, since we may now use the term "pass by reference" to refer to using reference types to pass an object by reference.
In a C++ context, the former use is, IMO, deprecated. However, I believe the former use is common in other contexts (e.g. pure C) where there is no ambiguity.
Does C even have ``pass by reference''?
Not really.
Strictly speaking, C always uses pass by value. You can simulate pass by reference yourself, by defining functions which accept pointers and then using the & operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function (by passing a pointer instead, see question 6.4 et al.).
Another way of looking at it is that if an parameter has type, say, int * then an integer is being passed by reference and a pointer to an integer is being passed by value.
Fundamentally, C has nothing truly equivalent to formal pass by reference or c++ reference parameters.
To demonstrate that pointers are passed by value, let's consider an example of number swapping using pointers.
int main(void)
{
int num1 = 5;
int num2 = 10;
int *pnum1 = &num1;
int *pnum2 = &num2;
int ptemp;
printf("Before swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
temp = pnum1;
pnum1 = pnum2;
pnum2 = ptemp;
printf("After swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}
Instead of swapping numbers pointers are swapped. Now make a function for the same
void swap(int *pnum1, int *pnum2)
{
int *ptemp = pnum1;
pnum1 = pnum2;
pnum2 = temp;
}
int main(void)
{
int num1 = 5;
int num2 = 10;
int *pnum1 = &num1;
int *pnum2 = &num2;
printf("Before swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
swap(pnum1, pnum2);
printf("After swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}
Boom! No swapping!
Some tutorials mention pointer reference as call by reference which is misleading. See the this answer for the difference between passing by reference and passing by value.
From the C99 standard (emphasis mine):
6.2.5 Types
20 Any number of derived types can be constructed from the object and function types, as
follows:
...
— A pointer type may be derived from a function type or an object type, called the referenced type. A pointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. A pointer type is a complete object type.
Based on the above, what your professor said makes sense and is correct.
A pointer is passed by value to functions. If the pointer points to a valid entity, its value provides a reference to an entity.
"Passing by reference" is a concept. Yes, you are passing the value of a pointer to the function, but in that instance the value of that pointer is being used to reference the variable.
Someone else used a screwdriver analogy to explain that it is wrong to refer to the passing of pointers as passing by reference, saying that you can screw a screw with a coin but that that doesn't mean you would call the coin a screw driver. I would say that is a great analogy, but they come to the wrong conclusion. In fact, while you wouldn't claim a coin was a screwdriver, you would still say that you screwed the screw in with it. i.e. even though pointers are not the same as c++ references, what you are using them to do IS passing by reference.
C passes arguments by value, period. However, pointers are a mechanism that can be used for effectively passing arguments by reference. Just like a coin can be used effectively as a screw driver if you got the right kind of screw: some screws slit are even chosen to operate well with coins. They still don't turn the coins into actual screw drivers.
C++ still passes arguments by value. C++ references are quite more limited than pointers (though having more implicit conversions) and cannot become part of data structures, and their use looks a lot more like the usual call-by-reference code would look, but their semantics, while very much catered to match the needs of call-by-reference parameters, are still more tangible than that of pure call-by-reference implementations like Fortran parameters or Pascal var parameters and you can use references perfectly well outside of function call contexts.
Your professor is right.
By value , it is copied.
By reference, it is not copied, the reference says where it is.
By value , you pass an int to a function , it is copied , changes to the copy does not affect the original.
By reference , pass same int as pointer , it is not copied , you are modifying the original.
By reference , an array is always by reference , you could have one billion items in your array , it is faster to just say where it is , you are modifying the original.
In languages which support pass-by-reference, there exists a means by which a function can be given something that can be used to identify a variable know to the caller until the called function returns, but which can only be stored in places that won't exist after that. Consequently, the caller can know that anything that will be done with a variable as a result of passing some function a reference to it will have been done by the time the function returns.
Compare the C and C# programs:
// C // C#
int x=0; int x=0;
foo(&x); foo(ref x);
x++; x++;
bar(); bar();
x++; x++;
boz(x); boz(x);
The C compiler has no way of knowing whether "bar" might change x, because
foo() received an unrestricted pointer to it. By contrast, the C# compiler
knows that bar() can't possibly change x, since foo() only receives a
temporary reference (called a "byref" in .NET terminology) to it and there
is no way for any copy of that byref to survive past the point where foo()
returns.
Passing pointers to things allows code to do the same things that can be done with pass-by-ref semantics, but pass-by-ref semantics make it possible for code to offer stronger guarantees about things it won't do.

Is this a generic function pointer and is it dangerous?

Learning and messing up with function pointers, I noticed a way to initialize void function pointers and cast them. Yet, although I don‘t receive any warning or error, either with GCC or VS’s compiler, I wanted to know whether it was dangerous or a bad practice to do this as I don't see this way of initializing function pointers often on the Internet. Moreover, do we call this generic function pointer?
#include <stdio.h>
#include <stdint.h>
#include <conio.h>
#define PAUSE (_getch())
uint16_t add(const uint16_t x, const uint16_t y) {
return x + y;
}
char chr(uint8_t test) {
return (char)test;
}
int main(void) {
void(*test)() = (void*)add;
const uint16_t x = 1, y = 1;
uint16_t value = ((uint16_t(*)())test)(x, y);
test = (void*)chr;
printf("%d\n", add(x, y)); // 2
printf("%d\n", value); // 2
printf("%c\n", ((char(*)())test)(100)); // d
PAUSE;
return 0;
}
Is this a generic function pointer
No, if I'm not terribly mistaken, there's no such thing as a "generic function pointer" in C.
and is it dangerous?
Yes, it is. It is evil.
There are a couple of things you need to know. First, unless you are running a system that conforms to POSIX,
void(*test)() = (void*)add;
is wrong. void * is a pointer-to-object type, and as such, it is not compatible with function pointers. (At least not in standard C -- as I mentioned, POSIX requires it to be compatible with function pointers too.)
The second thing is that void (*fp)() and void (*fp)(void) are different. The former declaration permits fp to take any number of parameters of any type, and the number of arguments and their types will be inferred when the compiler sees the first call to the function (pointer).
Another important aspect is that function pointers are guaranteed to be convertible across each other (AFAIK this manifests in them having the same representation and alignment requirements). This means that any function pointer can be assigned to (the address of) any function (after an appropriate cast), so long as you do not call a function through a pointer to an incompatible type. The behavior is well-defined if and only if you cast the pointer back to the original type before calling it.
So, if you want a "generic" function pointer, you can just write something like
typedef void (*fn_ptr)(void);
and then you could assign any pointer to function to an object of type fn_ptr. What you have to pay attention to is, again, the conversion to the right type when invoking the function, as in:
int add(int a, int b);
fn_ptr fp = (fn_ptr)add; // legal
fp(); // WRONG!
int x = ((int (*)(int, int))fp)(1, 2); // good
There are two serious problems here:
A cast from a function pointer to an object pointer (such as void *) triggers undefined behavior: in principle, it could crash your system (though in practice there are many systems where it will work fine). Instead of void *, it's better to use a function-pointer type for this purpose.
You're tricking the compiler into unknowingly passing an int to a function expecting a uint8_t. That's also undefined behavior, and it's very dangerous. Since the compiler doesn't know that it's doing this, it can't even take the most basic necessary steps to avoid smashing the stack — you're really gambling here. Similarly, this is a bit more subtle, but you're also tricking the compiler into passing two int-s into a function expecting two uint16_t-s.
And two lesser problems:
The notation for function pointer types on their own — e.g., in a cast — is confusing. I think it's better to use a typedef: typedef void (*any_func_ptr)(); any_func_ptr foo = (any_func_ptr)(bar).
It's undefined behavior to call a function pointer with a different signature than the actual function has. You can avoid that with careful coding — more careful than your current code — but it's tricky and risky.
You may corrupt the call stack with this, depending on the calling convention, specifically who's doing the cleanup: http://en.wikipedia.org/wiki/X86_calling_conventions With the callee cleanup, the compiler has no way of knowing how many variables you have passed on the stack at the point of cleanup, so passing the wrong number of parameters or parameters of the wrong size will end corrupting the call stack.
On x64, everyone uses the caller cleanup, so you're safe in this regard. The parameter values, however, will in general be a mess. In your example, on x64, they will be whatever was in the corresponding registers at the time.
C11 §6.3.2.3 (8) says:
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.
And §6.7.6.3 (15) says about compatible types of functions:
[…] 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. […]
So, if you had add and chr to take int arguments (an int has at least a width of 16 bit) that would be OK (if you didn't cast the function pointer to void *), but, as it is, it is UB.

Strange float? Pointer to a float in a struct

first time posting here
I'm currently porting some code for an embedded device. Basically getting everything to work with a new compiler (AVR-GCC) from an out-of-date existing proprietary compiler
I've come across this strange looking (to me anyway!) variable in a struct. I can't work out what it is with the parentheses. It is in a struct which is used for raw values:
float (*tc)( float value );
My IDE highlights 'value' as a compiler keyword, just like 'float' so I don't know if this is AVR-GCC specific?
This is then used in a function which has a float argument called 'reading' and it tries to return the following:
return (raw[rCN3].tc)( reading );
The line above actually causes the program to attempt to access out of bounds memory.
I haven't seen code like this before so was wondering if anyone could help me decipher it? It worked with the old compiler but is causing a problem with AVR-GCC
Thanks in advance. Alex
This is a function pointer. It points to a function that returns a float value and that has a float parameter.
Two things:
1) float (*tc)( float value ) is a function pointer to a function taking a float as a parameter, returning a float
2) 'value' is a keyword in C# and may also be in other languages; hence its highlighting. Check your editor language settings.
That is a function pointer variable.
tc is a pointer to a function, which takes a single float as argument and returns a `float.
The reason it accesses out of bounds memory is probably because rCN3 is out of bounds for the array raw.
That is a function pointer.
It means that tc holds the address of a function accepting a single float argument, and returning a float value.
For instance, you could set it to the standard library's sinf function, like so:
somestruct.tc = sinf;
somestruct.tc(3.14159265f / 2); /* This will return roughly 1.0f. */
Also, the ever-useful cdecl says:
declare tc as pointer to function (float) returning float

Resources