In CCS6 I couldn't run this program properly.
typedef volatile struct{
unsigned int pin_in;
unsigned int pin_out;
unsigned int pin_dir;
unsigned int pin_ren;
unsigned int pin_ds;
unsigned int pin_sel;
unsigned int reserved[10];
}io_hw_t;
//#define PABASE ((io_hw_t*) (0x200)) // this part is working
#define PABASE 0x200
#define PBBASE 0x220
io_hw_t *const io[] = {PABASE, PBBASE}; // error
The warning I get is:
" #145-D a value of type "int" cannot be used to initialize an entity
of type "io_hw_t *const "
How can I fix this ?
Provide explicit casting in initialization as:
io_hw_t *const io[] = {(io_hw_t *)PABASE, (io_hw_t *)PBBASE};
io is declared as as array of const pointer to io_hw_t. So each member must be a pointer. But PABASE is integer constant and needs to be explicitly casted to pointer.
Alternatively you can add the casts in your macros also as:
#define PABASE ((void *)0x200)
Related
I have a function as follows that processes the information contained in an array of type unsigned char:
unsigned char LRCsimple(unsigned char *p, createLRC , unsigned char length)
{
}
Works great for mostly unsigned char arrays.
Now, I have a signed array and when I use such a function and it works very well, but I have a warning when compiling the code:
> ../src/apptcpipserver.c:102:9: warning: pointer targets in passing argument 1 of 'LRCsimple' differ in signedness [-Wpointer-sign]
if (0x01 == LRCsimple(apptcpipserverData.cRxedData,0x00,(apptcpipserverData.cRxedData[0x02] - 0x02)))
If I want to avoid this warning, I think the optimal solution is to create a function similar to the one above, but for a signed array, as follows:
unsigned char signedLRCsimple(char *p, createLRC , unsigned char length)
{
}
Or is there something else I can do to avoid that warning message?
Strict aliasing rule allows unsigned char and char alias. Therefore you should be able reuse LRCsimple for processing char*.
Therefore signedLRCsimple could be implemented as:
unsigned char signedLRCsimple(char *p, createLRC xxx, unsigned char length)
{
return LRCsimple((unsigned char*)p, xxx, length);
}
To avoid forcing client to change their code to use signedLRCsimple you could use generic selection introduced in C11 in form of _Generic. Typically it is used to select a function pointer basing on the type of first argument of _Generic.
#define LRCsimple(p, xxx, length) \
_Generic((p), unsigned char*: LRCsimple, \
char *: signedLRCsimple)(p, xxx, length)
Whenever LRCsimple is called the generic selection selects between LRCsimple for unsigned char* and signedLRCsimple for char*. For other types an error is raised.
A part of the C program that I am writing includes initialization of an input table using sc_memset() function. The table is defined by a typedef struct as shown below.
typedef struct {
UINT32 switchnum;
UINT32 feedback[8];
UINT32 switch_output[8];
} SWITCH_CHECK_IN;
SWITCH_CHECK_IN switch_input_table;
All the table elements, that is switchnum, feedback and switch_output should be initialized to zero.The sc_memset function prototype to be used for initialization is :
extern void sc_memset (volatile unsigned char *dest, unsigned long n, unsigned char data);
I have written the initialization code and because of the type differences in SWITCH_CHECK_IN & volatile unsigned char, I have tried to do some casting as below (I have tried several cast statements) but everytime I get a 'passing arg 1 of sc_memeset from incompatible pointer type' error.
while( *(volatile unsigned char *) &switch_input_table) {
{
sc_memset( &switch_input_table, sizeof(switch_input_table), 0 );
}
I'm new to C so I am not quite sure if my general approach is correct. Kindly,
1. Where am I going wrong? Could you please show me the correct way.
2. What other methods can be used?
Thanks in advance.
You need to cast the pointer to struct into a pointer to unsigned char, just like you do in the while condition:
sc_memset( (unsigned char*)&switch_input_table, ...
You shouldn't need volatile in the cast - the function implicitly adds volatile type qualifier to the passed parameter. Why it has volatile, I have no idea - it's fishy code unless the function expects a hardware register etc as input.
I wrote a small piece of code to understand how the offsetof macro works in the background. Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
/* Getting the offset of a variable inside a struct */
typedef struct {
int a;
char b[23];
float c;
} MyStructType;
unsigned offset = (unsigned)(&((MyStructType * )NULL)->c);
printf("offset = %u\n", offset);
return 0;
}
However, if I run it I get a warning message:
WARNING: cast from pointer to integer of different size [-Wpointer-to-int-cast]
However, if I look at the original offsetof macro in c, the code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(void)
{
/* Getting the offset of a variable inside a struct */
typedef struct {
int a;
char b[23];
float c;
} MyStructType;
unsigned offset = offsetof(MyStructType, c);
printf("offset = %u\n", offset);
return 0;
}
So why do I get the warning as I cast to unsigned ? It appears to be the type for the offsetof macro. This is puzzling me.
As mch commented, unsigned is not the right type; it's 32-bit on pretty much all real-world systems. The offsetof macro is supposed to produce a result of type size_t, which is what you "should" be casting to here. I think you're confused by the code you found storing the result into an object of type unsigned; that's okay as long as they're sure the value is small, but it doesn't mean the type of the expression offsetof(MyStructType, c); was unsigned. C allows you to silently assign a larger integer type into a smaller one.
However, no matter what you do, this is not a valid implementation of offsetof and has undefined behavior (via applying -> to an invalid pointer). The way you get a working offsetof without UB is #include <stddef.h>.
This question already has answers here:
What does a typedef with parenthesis like "typedef int (f)(void)" mean? Is it a function prototype?
(6 answers)
Closed 4 years ago.
I was going through a code base and found this
typedef long long int (stoll_t)(const char *, char **, int);
Don't know what it does?
And how to call this function ?
is how it is in code
long long int argtoll( const char *str, const char **end, stoll_t stoll); //this
typedef long long int (stow)(const char *, char **, int); defines stow as a type.
That type is a function (pointer to const char, pointer to pointer to char, int) returning long long int.
long long int example_function_of_that_type(const char *a, char **b, int c) {
if (a == NULL) return 1;
if (b == NULL) return 2;
return c;
}
It defines an alias to function type
it works like shorter version of the declaration of the extern function.
example:
#include <stdio.h>
typedef int (stow)( int);
int main(void) {
// your code goes here
stow x;
printf("%d\n", x(5));
return 0;
}
and x has to be defined in other (or the same compilation unit).
Almost useless (at least I cant find any real use of it) - but definitely it makes code harder to read. So the only use is the code obfuscation or not hiding the function pointers.
stow *y; - does not hide the function pointer in the typedef.
Most programmers prefer actually to typedef the pointer to the function .
stow argtoll;
argtoll(/*... actual parameters */);
It's well known the use of typeof in Macros to make them type independent, such as container_of() and many other macros from the Linux kernel. It is unarguable that the typeof keyword unleashes a lot of power when used in these macros.
This question is about further use of the typeof keyword. What other contexts could the keyword bring lots of gain in C code, besides Macros?
One use of typeof is to const-cast a 2-dimensional array. In gcc, the construct:
extern void foo(const int a[2][2]); // or equivalently a[][2]
int a[2][2];
foo(a);
will generate:
"warning: passing argument 1 of 'foo' from incompatible pointer type".
(See http://c-faq.com/ansi/constmismatch.html for the reason why.) One way to fix this is to use a sledge-hammer-like cast, such as:
foo((void *)a);
Such a cast will happily take whatever you, perhaps mistakenly, give it.
But we can be much more delicate. By using the casting-macro CONST_CAST_2D given in the following code sample, the warning is eliminated. And more importantly, if you try to apply it to anything other than a 2-D array, you will get a compiler error/warning. CONST_CAST_PP works similarly, for a pointer-to-a-pointer.
#define CONST_CAST_2D(x) ((const typeof((x)[0][0])(*)[countof((x)[0])])(x))
#define CONST_CAST_PP(x) ((const typeof(**(x))**)(x))
#define countof(x) (sizeof(x) / sizeof 0[x]) // semi-standard define
static void foo(const int a[][2]) {} // takes const
static void bar(const int **b) {} // takes const
int main(void) {
int a[2][2]; // non-const
int **b; // non-const
foo(CONST_CAST_2D(a)); // ok
bar(CONST_CAST_PP(b)); // ok
return 0;
}
CONST_CAST_PP provides a clean and robust solution to a commonly-asked problem, e.g.:
Double pointer const-correctness warnings in C
c compiler warning when passing a char *arr[] to a function as const char **arr
What type is the reference to an array variable?
const cast and pointers to pointers
Why it's not safe to cast `char **` to `const char **`?
Why does implicit conversion from non-const to const not happen here?
Intel C++ Compiler warning 167 when non-const argument is passed as const parameter
And CONST_CAST_2D resolves:
How to eliminate warning for passing multidimensional array as const multidimensional array?
C function const multidimensional-array argument strange warning
A second usage of typeof is to generate pointers to constants, or pointers to function return values, as shown in the following example:
#include <stdio.h>
#include <time.h>
#include <sys/socket.h>
#define AMPERSAND(x) (&(typeof(x)){x})
int main(void) {
printf("%s\n", ctime(AMPERSAND(time(0)))); // pointer to time_t
setsockopt(0, SOL_SOCKET, SO_REUSEADDR, AMPERSAND(1), sizeof 1);
return 0;
}
This allows for straight-forward function composition, rather than having to save temporaries in named variables. (Unfortunately this doesn't extend to g++.)
Some people (myself included) dislike the syntax of the C++ const_cast<> operator, because;
It seems misnamed, because it removes const.
It seems to violate DRY, because it requires a redundant type arg.
But I am wrong: it is not misnamed, since it can also add const and/or volatile "cv" qualifiers, and it only partially violates DRY, since the compiler will catch any errors. So I dislike it slightly less and use it: it is safer than the C-style cast.
Using gcc's typeof, you can have almost the same type safety in C.
The following C code sample gives a CONST_CAST(T, x) macro, and illustrates its use:
#define REMOVE_QUALIFIER(cv, T, x) /* this macro evaluates its args only once */ \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), cv T), ((T)(x)), \
(void)0)
#define ADD_QUALIFIER(cv, T, x) /* this macro evaluates its args only once */ \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), T), ((cv T)(x)), \
(void)0)
#ifdef __GNUC__
#define CONST_CAST(T, x) REMOVE_QUALIFIER(const, T, x) // "misnamed"
#else
#define CONST_CAST(T, x) ((T)(x)) // fallback to standard C cast
#endif
void foo(void);
void foo(void) {
const int *a = 0;
const float *x = 0;
int *b = a; // warning
int *c = (int *)a; // no warning, unsafe standard cast
int *d = (int *)x; // no warning, and likely wrong
int *e = CONST_CAST(int *, a); // ok
int *f = CONST_CAST(int *, x); // error
unsigned *g = CONST_CAST(unsigned *, a); // error
const int **h = &b; // warning
const int **i = ADD_QUALIFIER(const, int **, &b); // ok
const int **j = ADD_QUALIFIER(const, int **, &x); // error
}
This technique can also be used to change the signedness of a type, reminiscent of C++'s std::make_signed and std::make_unsigned, or Boost traits. For example:
#define MAKE_UNSIGNED(T, x) ADD_QUALIFIER(unsigned, T, x) // T usually char*
This use of gcc's typeof is yet another reinterpret cast, using union-punning.
It can be applied to scalars and structures, as well as to pointers. It gives only an R-value.
#ifdef __GNUC__
#define PUN_CAST(T, x) (((union {typeof(x) src; T dst;})(x)).dst)
#else
#define PUN_CAST(T, x) (*(T*)&(x)) //<-- classic pun: breaks strict aliasing rules
#endif
Caveat: you can use this to cast a pointer into an array of 4 or 8 bytes, or vice versa. But you can't use it to cast a pointer into another pointer, in an attempt to avoid the strict aliasing rules.