I want to pass an int to a function that expects a char *.
The function header looks like this:
void swapEndian(char *pElement, unsigned int uNumBytes)
and calling the function with an int (I know, this won't work..)
int numLine;
swapEndian(numLine, sizeof(int));
So what must I do to numline to pass it to this function?
It sounds as though you just want:
swapEndian( (char*) &numLine, sizeof(int) );
The char* cast already suggested will work
swapEndian( (char*) &numLine, sizeof(int) );
...however if you can change swapEndian to take a void* it would be better since it avoids needing the cast (this is basically what void pointers are meant for) and also avoids any potential problems or potential future problems to do with the casting operation itself...
If swapEndian works with every pointers to object, then you can pass your pointer, because, according to the strict aliasing rule, a pointer to a character type can be dereference regardless to the type of the pointed object. You just need a typecast.
swapEndian((char *)&numLine, sizeof numLine);
C11 (n1570), § 6.5 Expressions
An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type
compatible with the effective type of the object,
— a type that is the
signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to
a qualified version of the effective type of the object,
— an
aggregate or union type that includes one of the aforementioned types
among its members (including, recursively, a member of a subaggregate
or contained union), or
— a character type.
In addition to other answers, assuming the swapEndian does what it name suggests, I believe it is wrongly declared. I suggest to declare it (if you can)
void swapEndian(void *pElement, size_t uNumBytes);
Related
I am learning about Undefined behavior in C. Now I got a little code snippet and thinking of if it is undefined behavior or not.
In my example I got a char *ptr. Let's imagine it has been initialized correctly.
Second, I got a function which takes a (double *dPtr). If I now pass my char pointer to that function, will it result in UB? Firstly, I doubt it.
If I now use that pointer in my function and access the value, will that result in undefined behavior or will it just be interpreted as double value? Even if the value is incorrect, can the char be interpreted as double, which is normal behavior?
//Passing char* instead of double*
void foo(double* dPtr) {
//UB ?
double d = (* dPtr - 15.0)/2.0;
}
int main()
{
char *string = "Hello World";
foo(string);
}
C 2018 6.5 7 says:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
Accessing an array of char as a double satisfies none of these, so the behavior is not defined by the C standard.
Additionally, when the pointer to char is converted to a pointer to double, if it is not suitably aligned for a double, the behavior is not defined by the C standard, by 6.3.2.3 7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined…
I want to understand the real need of having a void pointer, for example in the following code, i use casting to be able to use the same ptr in different way, so why is there really a void pointer if anything can be casted?
int main()
{
int x = 0xAABBCCDD;
int * y = &x;
short * c = (short *)y;
char * d = (char*)y;
*c = 0;
printf("x is %x\n",x);//aabb0000
d +=2;
*d = 0;
printf("x is %x\n",x);//aa000000
return 0;
}
Converting any pointer type to any other pointer type is not supported by base C (that is, C without any extensions or behavior not required by the C standard). The 2018 C standard says in clause 6.3.2.3, paragraph 7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer…
In that passage, we see two limitations:
If the pointer is not properly aligned, the conversion may fail in various ways. In your example, converting an int * to a short * is unlikely to fail since int typically has stricter alignment than short. However, the reverse conversion is not supported by base C. Say you define an array with short x[20]; or char x[20];. Then the array will be aligned as needed for a short or char, but not necessarily as needed for an int, in which case the behavior of (int *) x would not be defined by the C standard.
The value that results from the conversion mostly unspecified. This passage only guarantees that converting it back yields the original pointer (or something equivalent). It does not guarantee you can do anything useful with the pointer without converting it back—you cannot necessarily use a pointer converted from int * to access a short.
The standard does make some additional guarantees about certain pointer conversions. One of them is in the continuation of the passage above:
… When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
So you can use a pointer converted from int * to access the individual bytes that represent an int, and you can do the same to access the bytes of any other object type. But that guarantee is made only for access the individual bytes with a character type, not with a short type.
From the above, we know that after the short * c = (short *)y; in your example, y does not necessarily point to any part of the x it originated from—the value resulting from the pointer conversion is not guaranteed to work as a short * at all. But, even if it does point to the place where x is, base C does not support using c to access those bytes, because 6.5 7 says:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
So the *c = 0; in your example is not supported by C for two reasons: c does not necessarily point to any part of x or to any valid address, and, even if it does, the behavior of modifying part of the int x using short type is not defined by the C standard. It might appear to work in your C implementation, and it might even be supported by your C implementation, but it is not strictly conforming C code.
The C standard provides the void * type for use when a specific type is inadequate. 6.3.2.3 1 makes a similar guarantee for pointers to void as it does for pointers to objects:
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
void * is used with routines that must work with arbitrary object types, such as qsort. char * could serve this purpose, but it is better to have a separate type that clearly denotes no specific type is associated with it. For example, if the parameter to a function were char *p, the function could inadvertently use *p and get a character that it does not want. If the parameter is void *p, then the function must convert the pointer to a specific type before using it to access an object. Thus having a special type for “generic pointers” can help avoid errors as well as indicate intent to people reading the code.
Why void pointer if pointers can be casted into any type(in c)?
C does not specify that void* can be cast into a pointer of any type. A void * may be cast into a pointer to any object type. IOWs, a void * may be insufficient to completely store a function pointer.
need of having a void pointer
A void * is a universal pointer for object types. Setting aside pointers to const, volatile, etc. concerns, functions like malloc(), memset() provide universal ways to allocate and move/set data.
In more novel architectures, a int * and void * and others have different sizes and interpretations. void* is the common pointer type for objects, complete enough to store information to re-constitute the original pointer, regardless of object type pointed to.
So to clear out misunderstandings from the title (not sure how to ask the question in the title) I want to read from a file(char array), pass it as an void* so i can read undependable of datatype by incrementing the pointer. So here's an simple example of what I want to do in C code:
char input[] = "D\0\0Ckjh\0";
char* pointer = &input[0]; //lets say 0x00000010
char type1 = *pointer; //should be 'D'
pointer += sizeof(char); //0x00000020
uint16_t value1 = *(uint16_t*)pointer; //should be 0
pointer += sizeof(uint16_t); //0x00000040
char type2 = *pointer; //should be 'C'
pointer += sizeof(char); //0x00000050
uint32_t value2 = *(uint32_t*)pointer; //should be 1802135552
This is just for educational purpose, so I would just like to know if it is possible or if there is a way to achieve the same goal or something alike. Also the speed of this would be nice to know. Would it be faster to just keep the array and just make bitshifting on the chars as you read them or is this actually faster?
Edit: edit on the c code and changed void* to char*;
This is wrong in two ways:
void is an incomplete type that cannot be completed. An incomplete type is a type without a known size. In order to do pointer arithmetics, the size must be known. The same is true for dereferencing a pointer. Some compilers attribute the size of a char to void, but that's an extension you should never rely on. Incrementing a pointer to void is wrong and can't work.
What you have is an array of char. Accessing this array through a pointer of a different type violates strict aliasing, you're not allowed to do that.
That's actually not what your current code does -- looking at this line:
uint32_t value2 = (int)*pointer; //should be 1802135552
You're just converting the single byte (assuming your pointer points to char, see my first point) to an uint32_t. What you probably meant is
uint32_t value2 = *(uint32_t *)pointer; //should be 1802135552
which might do what you expect, but is technically undefined behavior.
The relevant reference for this second point is e.g. in §6.5 p7 in N1570, the latest draft for C11:
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
The reasoning for this very strict rule is for example that it enables compilers to do optimizations based on the assumption that two pointers of different types (except char *) can never alias. Other reasons include alignment restrictions on some platforms.
Even if you fix your code to cast pointer to correct type (like int *) before dereferencing it, you might have problems with alignment. For example on some architectures you simply can not read an 4-byte int if it is not aligned to 4-byte word boundary.
A solution which would definitely work is to use something like this:
int result;
memcpy(&result, pointer, sizeof(result));
UPDATE:
in the updated code in the question
uint16_t value1 = *(uint16_t*)pointer;
exactly violates strict aliasing. It's invalid code.
For more details, read the rest of the answer.
Initial version:
Technically, you are not allowed to dereference a void pointer in first place.
Quoting C11, chapter §6.5.3.2
[...] If the operand points to a function, the result is
a function designator; if it points to an object, the result is an lvalue designating the
object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. [...]
but, a void is a forever-incomplete type, so the storage size is not known, hence the dereference is not possible.
A gcc extension allows you to dereference the void pointer and perform arithmatic operation on them, considering it as alias for a char pointer, but better, do not reply on this. Please cast the pointer to either a character type or the actual type (or compatible) and then, go ahead with dereference.
That said, if you cast the pointer itself to some other type than a character type or an incompatible type with the original pointer, you'll violate strict aliasing rule.
As mentioned in chapter §6.5,
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
and, chapter §6.3.2.3
[....] When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object.
I have a function pointer whose function is declared as expecting char * arguments.Into it, I'd like to save a pointer to a function declared as taking char const* arguments.
I guess I can either use a wrapper or a cast.
Casts seem more straightforward, but can I legally call the result of such a function pointer cast?
Example code below:
static int write_a(char * X){
return 0;
}
static int write_b(char const* X){
return 0;
}
static int wrapped_write_b(char * X){
return write_b(X);
}
typedef int (*write_fn)(char * );
write_fn a = write_a;
write_fn b = wrapped_write_b;
write_fn b1 = (write_fn)write_b; //is b1 legally callable?
This is undefined behavior - You can use a pointer to call a function of another type only if the types are compatible (6.3.2.3/8):
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.
Two functions have compatible types if (simplified version) they have same return and arguments are compatible (6.7.6.3, Semantics/15):
For two function types to be compatible, both shall specify compatible return types.146) 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.
A const char * is not compatible with a char * (6.7.6.1, Semantics/2):
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
Since const char * and char * are not identically qualified, they are not compatible, and calling write_b through b is undefined behavior.
Strictly speaking, it is not allowed.
A pointer-to-something is not compatible with a pointer-to-qualified-something. Because a pointer-to-qualified-something is not a qualified type of pointer-to-something
The same applies for
pointer-to-function-accepting-something
and
pointer-to-function-accepting-qualified-something.
This can be found through C11 6.2.7 compatible type:
Two types have compatible type if their types are the same.
Additional rules for determining whether two types are compatible are
described in 6.7.2 for type specifiers, in 6.7.3 for type
qualifiers...
Where 6.7.3 is the relevant part. It says
For two qualified types to be compatible, both shall have the identically qualified version of a compatible type;
The conversion chapter 6.3.2.3 does not contradict this:
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.
EDIT
As noted in the answer by Holt, the compatibility of two functions is explicitly described in 6.7.6.3/15.
I still think that a wrapper function is the best solution. The root of the problem is that write_a isn't const-correct. If you can't change that function, then write a wrapper around it.
write_fn b1 = (write_fn)write_b; //is this legal?
Is what legal?
Function pointer types involved in this cast are not compatible.
Yet casting function pointer to an incompatible function pointer type is perfectly legal. However, the only thing you can do with such forcefully converted pointer is convert it back to the original type. The language specification guarantees that such round-trip conversion will preserve the original pointer value. This is why we can use, say, void (*)(void) as a "universal storage type" for function pointers (like void * for data pointers). It can be used for storing function pointers of any type (but not for calling the functions). To perform such pointer storage (and retrieval) we'll have to use explicit casts, just like the one in your code. There's nothing illegal about it.
Meanwhile, trying to call the function through b1 will result in undefined behavior, specifically because the pointer type is not compatible with the actual function type.
In your question you clearly state that you want to "save" the pointer to that function. As long as we are talking only about "saving" (storing) the pointer, your code is perfectly flawless.
The malloc() function returns a pointer of type void*. It allocates memory in bytes according to the size_t value passed as argument to it. The resulting allocation is raw bytes which can be used with any data type in C(without casting).
Can an array with type char declared within a function that returns void *, be used with any data type like the resulting allocation of malloc?
For example,
#include <stdio.h>
void *Stat_Mem();
int main(void)
{
//size : 10 * sizeof(int)
int buf[] = { 1,2,3,4,5,6,7,8,9,10 };
int *p = Stat_Mem();
memcpy(p, buf, sizeof(buf));
for (int n = 0; n < 10; n++) {
printf("%d ", p[n]);
}
putchar('\n');
return 0;
}
void *Stat_Mem()
{
static char Array[128];
return Array;
}
The declared type of the static object Array is char. The effective type of this object is it's declared type. The effective type of a static object cannot be changed, thus for the remainder of the program the effective type of Array is char.
If you try to access the value of an object with a type that is not compatible with, or not on this list1, the behavior is undefined.
Your code tries to access the stored value of Array using the type int. This type is not compatible with the type char and is not on the list of exceptions, so the behavior is undefined when you read the array using the int pointer p:
printf("%d ", p[n]);
1 (Quoted from: ISO:IEC 9899:201X 6.5 Expressions 7 )
An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:
— a type
compatible with the effective type of the object,
— a qualified
version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the
effective type of the object,
— a type that is the signed or unsigned
type corresponding to a qualified version of the effective type of the
object,
— an aggregate or union type that includes one of the
aforementioned types among its members (including, recursively, a
member of a subaggregate or contained union), or
— a character type.
No you cannot use an arbitrary byte array for an arbitrary type because of possible alignment problems. The standard says in 6.3.2.3 Conversions/Pointers (emphasize mine):
A pointer to an object or incomplete type may be converted to a pointer to a different
object or incomplete type. If the resulting pointer is not correctly aligned for the
pointed-to type, the behavior is undefined. Otherwise, when converted back again, the
result shall compare equal to the original pointer.
As a char as the smallest alignment requirement, you cannot make sure that your char array will be correctly aligned for any other type. That is why malloc guarantees that a buffer obtained by malloc (even if it is a void *) has the largest possible alignement requirement to be able to accept any other type.
I think that
union {
char buf[128];
long long i;
void * p;
long double f;
};
should have correct alignment for any type as it is compatible with largest basic types (as defined in 6.2.5 Types). I am pretty sure that it will work for all common implementations (gcc, clang, msvc, ...) but unfortunately I could not find any confirmation that the standard allows it. Essentially because of the strict aliasing rule as defined in 6.5 Expression §7:
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
a type compatible with the effective type of the object,
a qualified version of a type compatible with the effective type of the object,
a type that is the signed or unsigned type corresponding to the effective type of the
object,
a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
a character type.
So IMHO there is not portable and standard conformant way to build a custom allocator not using malloc.
If one reads the rationale of the C89 Standard, the only reason that the type- aliasing rules exist is to avoid requiring compilers to make "worst-case aliasing assumptions". The given example was:
int a;
void f( double * b )
{
a = 1;
*b = 2.0;
g(a);
}
If program creates a "char" array within a union containing something whose alignment would be suitable for any type, takes the address thereof, and never accesses the storage of that structure except through the resulting pointer, there should be no reason why aliasing rules should cause any difficulty.
It's worthwhile to note that the authors of the Standard recognized that an implementation could be simultaneously compliant but useless; see the rationale for C89 2.2.4.1:
While a deficient implementation could probably contrive a program that meets this requirement, yet still succeed in being useless, the Committee felt that such ingenuity would probably require more work than making something useful. The sense of the Committee is that implementors should not construe the translation limits as the values of hard-wired parameters, but rather as a set of criteria by which an implementation will be judged.
While that particular statement is made with regard to implementation limits, the only way to interpret the C89 as being even remotely compatible with the C dialects that preceded it is to regard it as applying more broadly as well: the Standard doesn't try to exhaustively specify everything that a program should be able to do, but relies upon compiler writers' exercising some common sense.
Use of a character-type array as a backing store of any type, assuming one ensures alignment issues are taken care of, shouldn't cause any problems with a non-obtusely written compiler. The Standard didn't mandate that compiler writers allow such things because they saw no reason to expect them to do otherwise. Unfortunately, they failed to foresee the path the language would take in the 21st Century.