Can someone please help me understand what this is doing:
alt_up_sd_card_dev *dev = (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
if (dev != NULL)
{
aux_status_register = ((short int *) SD_CARD_AUX_STATUS(dev->base));
}
I understand that the (short int *) is "type-casting" (as explained to me by some other helpful people on this forum) what SD_CARD_AUX_STATUS should be when the contents are called, but I've never seen the dev->base syntax before....
1.Here dev, is structure pointer. This pointer gets the memory from this line (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
2.The structure alt_up_sd_card_dev may have member called base.
3.SD_CARD_AUX_STATUS could be macro, which does some manipulation on dev->base pointer.
For more information, check the parameterised MACRO concepts in C
We can't give you a proper answer without knowing all the include files this references, but by general convention:
1) By standard C naming conventions, the all-uppercase SD_CARD_AUX_STATUS() is a macro rather than a function. The macro is set up by a #define either earlier in this file or in one of the #included .h files. Look for that definition to find out what it's actually doing.
2) -> is like . but for pointers-to-structures rather than structures. That is, if you have a struct { int foo, bar; } baz, then baz.foo is the same thing as (&baz)->foo Or, as Wikipedia puts it:
Structure dereference ("member b of object pointed to by a") a->b
Structure reference ("member b of object a") a.b
This is not related to C syntax in general. This piece of code is very specific.
I can only guess what it does.
alt_up_sd_card_dev *dev = (alt_up_sd_card_dev *) alt_find_dev(name, &alt_dev_list);
This calls a function alt_find_dev which probably looks for a device. The device is apparently an sd card reader... The result of the function is cast to a specific type of pointer. Probably the result is of generic pointer type and it is cast to a pointer to a structure that describes specifically an sd card device. It is then stored in the dev variable.
if (dev != NULL)
if the device is found....
aux_status_register = ((short int *) SD_CARD_AUX_STATUS(dev->base));
a macro SD_CARD_AUX_STATUS is called with a parameter dev->base (where base is a field in the structure describing the sd card device). The operator -> is called pointer dereference and it is simillar to . operator. It allows to access fields of a struct which is pointed by the pointer. The macro returns some kind of a status of the device. Hard to tell why it is cast to a pointer to short int, but the result is stored in a variable aux_status_register.
Without additional information it's impossible to tell anything more about the code.
dev is a pointer to a data structure in memory - called a struct in C. A struct has members - a set of variables within it. dev->base means access the member called base within the struct of type alt_up_sd_card_dev which dev is pointing to.
Look for the definition of struct alt_up_sd_card_dev which you will find in one of the header files included from the one you are looking at.
In general the -> operator is said to de-reference the pointer.
SD_CARD_AUX_STATUS is probably a macro - traditionally these are named all upper case. It might perform some kind of conversion or even call a function. Search for its definition in the headers.
Related
I came across older code in a project that declares a struct in the H file as
struct A {
const int i;
};
Now the function that creates struct A pointers internally looks like this
struct A * newStructA ( int i ) {
struct B * ptr = malloc(sizeof(struct B));
ptr->i = i;
return (struct A *)ptr;
}
and struct B is declared in the C file and looks like this:
struct B {
int i;
};
Question 1: Is that even allowed according to C standard? Sure, the data type of i is the same and the struct should have the same memory layout, but is that guaranteed or could the const modifier also change the memory layout on certain systems?
Question 2: Knowing that all struct A * pointers the code deals with are in fact struct B * pointers, would it be allowed to cast the pointers back to struct B * and then modify the int value? The declaration says it is const, but I know for sure that it isn't as it's always located in modifiable heap memory. Or could that have implications as the C compiler may rely on the value being constant, so it assumes it cannot ever change and thus if two lines of code contain ptr->i the compiler may not even fetch the value a second time as how could it have changed if it is const? As that would lead to very hard to trace bugs that may only be seen if a certain optimization level is being used.
Question 3: Is there a better way to achieve a const value that external code cannot directly change (or at least should never try to), yet internal code can change as the value is in fact not const at all? The only way I can think of would be to hide the struct layout altogether (struct A;) but then I need to provide a function like int getI(struct A * ptr) and always access the value using that function.
Are you allowed to modify a C value that claims to be const if you know for sure that it actually isn't constant?
Yes.
Is that even allowed according to C standard?
Yes.
is that guaranteed or could the const modifier also change the memory layout on certain systems?
It could, when defining the variable as const the variable will typically be placed in a different memory region that is read-only.
Knowing that all struct A * pointers the code deals with are in fact struct B * pointers, would it be allowed to cast the pointers back to struct B * and then modify the int value?
It is unclear. Can you safely cast a C structure with non-const members to an equivalent structure with const members?
Or could that have implications as the C compiler may rely on the value being constant, so it assumes it cannot ever change and thus if two lines of code contain ptr->i the compiler may not even fetch the value a second time as how could it have changed if it is const?
Yes. Related https://stackoverflow.com/a/20707255/9072753 .
Is there a better way to achieve a const value that external code cannot directly change (or at least should never try to), yet internal code can change as the value is in fact not const at all?
This is C. The spirit of C says https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2086.htm :
(1) Trust the programmer.
(2) Don't prevent the programmer from doing what needs to be done.
In my opinion, a better way is not to hide and just use struct with non-const members. A C programmer will be able to access it anyway.
The only way I can think of would be to hide the struct layout altogether (struct A;) but then I need to provide a function like int getI(struct A * ptr)
Yes, hiding something will cause runtime overhead. FILE * has been with us since forever, and the members of FILE are visible to user code in many implementations. Yet no one uses them.
To achieve that a value should not be changed by external code, write a specification of your library that external code should not do it.
To hide your proprietary code, use accessors and let users operate only on pointers to your data with PIMPL idiom.
C 2011 draft
6.7.3 Type qualifiers ... 6 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with
non-const-qualified type, the behavior is undefined. If an attempt is
made to refer to an object defined with a volatile-qualified type
through use of an lvalue with non-volatile-qualified type, the behavior
is undefined.133) 133) This applies to those objects that behave as if
they were defined with qualified types, even if they are never actually
defined as objects in the program (such as an object at a memory-mapped
input/output address).
I'm wondering if there's a better way to handling pointers to multiple structs, when you use the structs to overlay data you didn't create yourself. I'm trying to parse an ELF file header (the format is well-known, so I won't reproduce the structs here). So, say you have a pointer to a struct for the file header:
struct elf64_file_hdr *fh;
One of the fields of the file header is `shoff', which is the offset in bytes from the start of the file to the beginning of section headers, or to be more specific, the beginning of an array of section header structs. So, you can have:
struct elf64_section_header *sh;
and access each section header as sh[0], sh[1], etc. The question, then, is how to set `sh' correctly. I've been doing a cast and then recast to make the pointer math work:
sh = (struct elf64_sec_hdr *)((char *)fh + fh->fh_shoff);
But it seems like there must be a more elegant way to do this.
I don't think there is, beyond wrapping it in a macro. But that doesn't seem too bad. To get around pointer arithmetic you first have to cast away the initial type, then you need to cast the result to the type you want. That's exactly what you're doing.
Here's a macro to do it, casting the result to void* so it will automatically convert to the right type.
#define AT_OFFSET(base, offset) ((void*)((char*)(base) + (offset)))
...
struct elf64_sec_hdr *sh = AT_OFFSET(fh, fh->fh_shoff);
I saw the following weird type of macro in C (Linux) code here:
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
What does ((t*)0)->f) do?
How does it work?
The thing does exactly what the name suggests – deliver the size of a field of a struct.
what it first does is cast 0 (which is an arbitrary address) to a pointer of the type of struct.
Then it -> (access via pointer) takes the field and applies sizeof to it.
Pretty straightforward!
It does what it says on the tin, like Marcus Müller explains. If you are wondering why bother with it, why can't we just do sizeof(type_of_field) instead, then consider this:
struct foo {
struct {
int a;
float b;
} bar;
};
We cannot name type_of_bar, since for the programmer it has no name. But the macro allows us to obtain the field size via a workaround, regardless.
Because sizeof is computed at compile time (except in the case of variable length arrays, which is not the case here) its argument is not evaluated at runtime. It is therefore OK to cast a NULL pointer, as it's only used to indicate the field for which size is being computed.
I have a question about some code in Eric Roberts' Programming Abstractions in C. He use several libraries of his own both to simplify things for readers and to teach how to write libraries. (All of the library code for the book can be found on this site.)
One library, genlib provides a macro for generic allocation of a pointer to a struct type. I don't understand part of the macro. I'll copy the code below, plus an example of how it is meant to be used, then I'll explain my question in more detail.
/*
* Macro: New
* Usage: p = New(pointer-type);
* -----------------------------
* The New pseudofunction allocates enough space to hold an
* object of the type to which pointer-type points and returns
* a pointer to the newly allocated pointer. Note that
* "New" is different from the "new" operator used in C++;
* the former takes a pointer type and the latter takes the
* target type.
*/
#define New(type) ((type) GetBlock(sizeof *((type) NULL)))
/* GetBlock is a wrapper for malloc. It encasulates the
* common sequence of malloc, check for NULL, return or
* error out, depending on the NULL check. I'm not going
* to copy that code since I'm pretty sure it isn't
* relevant to my question. It can be found here though:
* ftp://ftp.awl.com/cseng/authors/roberts/cs1-c/standard/genlib.c
*/
Roberts intends for the code to be used as follows:
typedef struct {
string name;
/* etc. */
} *employeeT;
employeeT emp;
emp = New(employeeT);
He prefers to use a pointer to the record as the type name, rather than the record itself. So New provides a generic way to allocate such struct records.
In the macro New, what I don't understand is this: sizeof *((type)) NULL). If I'm reading that correctly, it says "take the size of the dereferenced cast of NULL to whatever struct type type represents in a given call". I think I understand the dereferencing: we want to allocate enough space for the struct; the size of the pointer is not what we need, so we dereference to get at the size of the underlying record-type. But I don't understand the idea of casting NULL to a type.
My questions:
You can cast NULL? What does that even mean?
Why is the cast necessary? When I tried removing it, the compiler says error: expected expression. So, sizeof *(type) is not an expression? That confused me since I can do the following to get the sizes of arbitrary pointers-to-structs:
#define struct_size(s_ptr) do { \
printf("sizeof dereferenced pointer to struct %s: %lu\n", \
#s_ptr, sizeof *(s_ptr)); \
} while(0)
Edit: As many people point out below, the two examples aren't the same:
/* How genlib uses the macro. */
New(struct MyStruct*)
/* How I was using my macro. */
struct MyStruct *ptr; New(ptr)
For the record, this isn't homework. I'm an amateur trying to improve at C. Also, there's no problem with the code, as far as I can tell. That is, I'm not asking how I can do something different with it. I'm just trying to better understand (1) how it works and (2) why it must be written the way it is. Thanks.
The issue is that the macro needs to get the size of the type pointed at by the pointer type.
As an example, suppose that you have the the pointer type struct MyStruct*. Without removing the star from this expression, how would you get the size of struct MyStruct? You couldn't write
sizeof(*(struct MyStruct*))
since that's not legal C code.
On the other hand, if you had a variable of type struct MyStruct*, you could do something like this:
struct MyStruct* uselessPointer;
sizeof(*uselessPointer);
Since sizeof doesn't actually evaluate its argument (it just determines the static size of the type of the expression), this is safe.
Of course, in a macro, you can't define a new variable. However, you could make up a random pointer to a struct MyStruct* by casting an existing pointer. Here, NULL is a good candidate - it's an existing pointer that you can legally cast to a struct MyStruct*. Therefore, if you were to write
sizeof(* ((struct MyStruct*)NULL))
the code would
Cast NULL to a struct MyStruct*, yielding a pointer of static type struct MyStruct*.
Determine the size of the object that would be formed by dereferencing the pointer. Since the pointer has type struct MyStruct*, it points at an object of type struct MyStruct, so this yields the type of struct MyStruct.
In other words, it's a simple way to get an object of the pointer type so that you can dereference it and obtain an object of the underlying type.
I've worked with Eric on some other macros and he is a real pro with the preprocessor. I'm not surprised that this works, and I'm not surprised that it's tricky, but it certainly is clever!
As a note - in C++, this sort of trick used to be common until the introduction of the declval utility type, which is a less-hacky version of this operation.
Hope this helps!
It's a hack. It relies on the fact that the argument to the sizeof operator isn't actually evaluated.
To answer your specific questions:
Yes, NULL is just a pointer literal. Like any other pointer, it may be cast.
sizeof operates on either a type or an expression. *(type) would be neither (after macro substitution has occurred), it would be a syntax error.
Consider the following C code:
typedef char * MYCHAR;
MYCHAR x;
My understanding is that the result would be that x is a pointer of type "char". However, if the declaration of x were to occur far away from the typedef command, a human reader of the code would not immediately know that x is a pointer. Alternatively, one could use
typedef char MYCHAR;
MYCHAR *x;
Which is considered to be better form? Is this more than a matter of style?
If the pointer is never meant to be dereferenced or otherwise manipulated directly -- IOW, you only pass it as an argument to an API -- then it's okay to hide the pointer behind a typedef.
Otherwise, it's better to make the "pointerness" of the type explicit.
I would use pointer typedefs only in situations when the pointer nature of the resultant type is of no significance. For example, pointer typedef is justified when one wants to declare an opaque "handle" type which just happens to be implemented as a pointer, but is not supposed to be usable as a pointer by the user.
typedef struct HashTableImpl *HashTable;
/* 'struct HashTableImpl' is (or is supposed to be) an opaque type */
In the above example, HashTable is a "handle" for a hash table. The user will receive that handle initially from, say, CreateHashTable function and pass it to, say, HashInsert function and such. The user is not supposed to care (or even know) that HashTable is a pointer.
But in cases when the user is supposed to understand that the type is actually a pointer and is usable as a pointer, pointer typedefs are significantly obfuscating the code. I would avoid them. Declaring pointers explicitly makes code more readable.
It is interesting to note that C standard library avoids such pointer typedefs. For example, FILE is obviously intended to be used as an opaque type, which means that the library could have defined it as typedef FILE <some pointer type> instead of making us to use FILE * all the time. But for some reason they decided not to.
I don't particularly like typedef to a pointer, but there is one advantage to it. It removes confusion and common mistakes when you declare more than one pointer variable in a single declaration.
typedef char *PSTR;
...
PSTR str1, str2, str3;
is arguably clearer than:
char *str1, str2, str3; // oops
I prefer leaving the *, it shows there's a pointer. And your second example should be shortened as char* x;, it makes no sense.
I also think this is a matter of style/convention. In Apple's Core Graphics library they frequently "hide" the pointer and use a convention of appending "Ref" to the end of the type. So for example, CGImage * corresponds to CGImageRef. That way you still know it's a pointer reference.
Another way to look at it is from the perspective of types. A type defines the operations that are possible on that type, and the syntax to invokes these operations. From this perspective, MYCHAR is whatever it is. It is the programmers responsibility to know the operations allowed on it. If it is declared like the first example, then it supports the * operator. You can always name the identifier appropriately to clarify it's use.
Other cases where it is useful to declare a type that is a pointer is when the nature of the parameter is opaque to the user (programmer). There may be APIs that want to return a pointer to the user, and expect the user to pass it back to the API at some other point. Like a opaque handle or a cookie, to be used by the API only internally. The user does not care about the nature of the parameter. It would make sense not to muddy the waters or expose its exact nature by exposing the * in the API.
If you look at several existing APIs, it looks as if not putting the pointerness into the type seems better style:
the already mentionned FILE *
the MYSQL * returned by MySQL's mysql_real_connect()
the MYSQL * returned by MySQL's mysql_store_result() and mysql_use_result()
and probably many others.
For an API it is not necessary to hide structure definitions and pointers behind "abstract" typedefs.
/* This is part of the (hypothetical) WDBC- API
** It could be found in wdbc_api.h
** The struct connection and struct statement ar both incomplete types,
** but we are allowed to use pointers to incomplete types, as long as we don't
** dereference them.
*/
struct connection *wdbc_connect (char *connection_string);
int wdbc_disconnect (struct connection *con);
int wdbc_prepare (struct connection * con, char *statement);
int main(void)
{
struct connection *conn;
struct statement *stmt;
int rc;
conn = wdbc_connect( "host='localhost' database='pisbak' username='wild' password='plasser'" );
stmt = wdbc_prepare (conn, "Select id FROM users where name='wild'" );
rc = wdbc_disconnect (conn);
return 0;
}
The above fragment compiles fine. (but it fails to link, obviously)
Is this more than a matter of style?
Yes. For instance, this:
typedef int *ip;
const ip p;
is not the same as:
const int *p; // p is non-const pointer to const int
It is the same as:
int * const p; // p is constant pointer to non-const int
Read about const weirdness with typedef here typedef pointer const weirdness