I am running this c program in gcc.
The below works for one variable.
#define dataBlk_tx0 ((volatile unsigned int *) 0x20000ACB)
But if I want to create an array and write to it how would I do this, this array needs to be defined before main?
#define dataBlk_tx0 ((volatile unsigned int * x[8]) 0x20000ACB)
main{
dataBlk_tx0[0] = 5;
}
If you want to read or write directly to that address and memory, you can do it like this:
Initialize dataBlk_tx0 as a pointer to the specific memory location
Access that memory through the pointer.
volatile unsigned int * dataBlk_tx0 = (unsigned int *)0x20000ACB;
int main () {
dataBlk_tx0[0] = 5;
return 0;
}
If you want to create an array in a specific memory region (like Flash vs RAM on a micocontroller), then you'll need to look into linker scripts.
Related
I'm working on an application that needs to convert any type of the variable from big to little-endian.
My system works with different variable types (16, 32, and 64 bits wide), and I need to be able to change the endianness with a single function. I wrote a function that manages to swap bytes in any variable however, I'm not happy with it. It works, but it requires dereferencing void pointers, which are prone to error with the double star...
Is there any better way to approach the problem?
Is there any way to avoid void pointers as return value? I was thinking about switch-case loop (eg. case 4 bytes -> return int32) however, I don't know how to write a function prototype for a function that returns different values.
My function:
void* swapBytes(void* number, int bytes_num){
void* swapped;
unsigned __int8* single_byte_ptr;
swapped = malloc(bytes_num * sizeof(__int8));
for (int i = 0; i<bytes_num; i++){
single_byte_ptr =((unsigned __int8*)number)+i; //get current byte
*( (__int8*)(swapped)+((bytes_num-1)-i)) = (unsigned __int8)*single_byte_ptr; //save the byte in new position
}
return swapped;
}
the way I call this function
__int64 big_number = 35169804487071;
big_number = *(__int64*)(swapBytes(&big_number, 8));
One problem you have is that you're leaking memory. You return a pointer to malloc'ed memory, but you're not saving the pointer when you return.
Given that you're assigning the result back to the same value, you're better off updating the existing variable, swapping the current byte with a byte on the "opposite" side.
You also don't need to use a void * anyplace other than the parameter type. Inside of the function, just use a pointer to an unsigned char or unsigned __int8 to work through the bytes.
void swapBytes(void* number, int bytes_num)
{
unsigned __int8* ptr = number;
for (int i = 0; i<bytes_num/2; i++) {
unsigned __int8 tmp = ptr[i];
ptr[i] = ptr[bytes_num-1-i];
ptr[bytes_num-1-i] = tmp;
}
}
Then call it like this:
swapBytes(&big_number, sizeof(big_number));
Your solution is very over-engineered and also entirely unsuitable for embedded systems such as MPC57xx.
Any integer type can get safely iterated across using a pointer to character. Assuming uint8_t* is a character type for your compiler, it's as simple as this:
void little_to_big16 (uint8_t big [sizeof(uint16_t)],
const uint8_t little [sizeof(uint16_t)])
{
big[0] = little[1];
big[1] = little[0];
}
Then write big_to_little16, big_to_little32 etc etc as needed. Such functions can and should probably be inlined too.
Example of use:
#include <stdio.h>
#include <inttypes.h>
void little_to_big16 (uint8_t big [sizeof(uint16_t)],
const uint8_t little [sizeof(uint16_t)])
{
big[0] = little[1];
big[1] = little[0];
}
int main (void)
{
uint16_t little = 0xAABB;
uint16_t big;
little_to_big16((uint8_t*)&big, (uint8_t*)&little);
printf("%"PRIx16, big);
}
Output on x86 little endian:
bbaa
I used type modifiers(far,near,huge) with normal variables rather than pointers and found that these pointer type modifiers are only applicable for the global normal variable but an error is generated when used with a variable local to a block.
int near a,far b,huge c;
int main()
{
int d,e,f;
// int near a,far b,,huge c;
// long int near a,far b,huge c;
// long long int near a,far b,huge c;
//printf("\n size of a=%d ,b=%d ,c=%d ,d=%d ,e=%d ,f=%d",sizeof(a),sizeof(b),sizeof(c),sizeof(d),sizeof(e),sizeof(f));
printf("\n address of a=%u ,b=%u ,c=%u ,d=%u ,e=%u,f=%u",&a,&b,&c,&d,&e,&f);
return 0;
}
why is this allowed with a global variable and not with a local variable. Additionally, what does the variable finally becomes i.e. it becomes a pointer,an integer with greater range or entirely something else.
near, far, and huge affect where, and in what type of memory, a variable is stored. Since local variables are always stored on the stack, using these modifiers on local variables doesn't make any sense.
Note that these features are all unique to the 16-bit DOS platform. They are not used on modern systems -- you can safely ignore them.
Everything that is placed on the stack can't be far modified.
You can place "non-far variables" in the stack, but not "far variables".
You can place "non-far pointers to non-far data" in the stack, but not "far pointers to non-far data**".
You can place "non-far pointers to far data" in the stack, but not "far pointers to far data".
Try this:
far int var = 0; /* OK */
far int far* far_var_ptr = &var; /* OK: far pointer to far data*/
int far* var_ptr = &var; /* OK: non-far pointer to far data*/ */
int main()
{
int far* var_ptr2 = &var; /* OK: Non-far ptr to far data */
far int far* far_var_ptr2 = &var; /* Fail: far ptr to far data */
far int var2 = 0; /* Fail: far data */
}
The key is that you can't define far data on the stack. Variables on the stack are:
Placed within a defined range of memory
Its exact location depends on the call stack before: it can't be known at compile time
This is not a far data:
int far* var;
It is an non-modified pointer to far data. The pointer itself is just a number not far modified that points to data in a far segment (platform specific).
This is far data:
far int* var;
And this too:
far int far* var;
The storage (far, near, huge) modifier of a variable (or function) is placed before the variable type.
Below I have to examples of code that do the same thing and give the same output. In the first, I use pointer to pointer argument passing to eliminate the use of ans as a global. In the second, I madeans a global which eliminated the additional uses of * when dealing with pointer to pointer:
Example 1:
// pointer to pointer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
unsigned char serial[] = {
0x1,0x2,0x3,0x4
};
void checkSerial(unsigned char* buf, unsigned char ** ans)
{
int i;
unsigned char *part;
part = 0;
i=2;
part = &buf[i];
*ans = (unsigned char*)malloc(2);
memset(*ans,0,2);
memcpy(*ans,part,2);
printf("0x%x\n",**ans);
++(*ans);
printf("0x%x\n",**ans);
}
int main(void)
{
unsigned char *ans, *buf;
while(1)
{
buf = malloc(4);
memset(buf,0,4);
memcpy(buf, serial, sizeof(serial));
checkSerial(buf, &ans);
--ans;
printf("the value is 0x%x\n", *ans);
free(buf);
free(ans);
sleep(3);
}
return 0;
}
Example 2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
unsigned char serial[] = {
0x1,0x2,0x3,0x4
};
unsigned char ans[2];
void checkSerial(unsigned char* buf)
{
int i;
unsigned char *part;
part = 0;
i=2;
part = &buf[i];
int j;
for(j=0;j<2;j++)
{
ans[j] = part[j];
}
printf("0x%x\n",*ans);
++(*ans);
printf("0x%x\n",*ans);
}
int main(void)
{
unsigned char *buf;
while(1)
{
buf = malloc(4);
memset(buf,0,4);
memcpy(buf, serial, sizeof(serial));
checkSerial(buf);
printf("the value is 0x%x\n", *ans);
free(buf);
sleep(3);
}
return 0;
}
Which technique is preferred in C?
Avoid global variables when it is not necessary. Going with first example is preferable.
Global variables are easily accessible by every functions, they can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
Keep variables as close to the scope they are being used in as possible. This prevents unexpected values for your variables and potential naming issues.
I personally don't like defining global variable where there is ways to avoid it.
But some guys say that, the concept of pointer is very much confusing. I don't feel that though..
My advice, if you get confuse with pointers try to avoid it with defining global variable. Otherwise, use pointers... :)
TL;DR: Solutions 1 and 2 are both bad.
The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time, if those are really known at compile-time then , just don't use malloc at all, declare variables on the stack. In C, generally avoid dynamic memory allocation as much as possible and prefer to create buffers which can hold the maximum size a buffer can have in your application. That avoids this kind of problems in the first place. The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time. The only place where dynamic memory allocation can be useful is for buffers whose sizes are unknown at compile-time, but you can still avoid it (see below). If buf is an incoming message, and ans the answer to this message, the size of ans can be unknown at compile-time, at least if you use variable-length messages.
Your version 2 is not working and can not work! First you declared ans to be an array of size 1 and iterate over it until index 2(now you edited that). Second to declare the array ans as global you would need to know its size at compile-time, and then of course if you knew its size at compile-time you would just declare the array ans in the function checkSerial. Moreover, when you declare a variable which is used by several functions in C don't forget to declare it static, otherwise it can be accessed from all files in your project.
A solution avoiding dynamic allocation, notice you avoid the disadvantages of your 2 solutions: the pointer to pointer and the global variable, and moreover your program can not leak since you don't use dynamic allocation:
enum {MSG_MAX_SIZE = 256 };
typedef struct message {
uint8_t payload[MSG_MAX_SIZE];
size_t msg_size;
} message_t;
void checkSerial(const message_t *buf, message_t *ans)
{
//parse buf and determine size of answer
...
...
//fill answer payload
ans->msg_size = buf[42];
}
int main(void)
{
while (1) {
message_t buf;
getMsg(&buf);
message_t ans;
checkSerial(&buf, &ans);
}
}
foo.c
#include "main.h"
unsigned char currentBar;
struct foo myFoo[getNumBars()];
void initMyFoo(void)
{
currentBar=(getNumBars()-1);
for(i=0; i<(sizeof(myFoo)/sizeof(myFoo[0])); i++)
{
myFoo[i].we = 1;
myFoo[i].want = 0;
myFoo[i].your = 0;
myFoo[i].soul = 0;
}
}
main.c
#include "foo.h"
unsigned char getNumBars()
{
return getDipSwitchValues();
}
initMyFoo();
(struct foo is declared in foo.h.)
This code has to execute without hard coding a number for Bars, as the number of Bars will change according to whatever the user sets his DIP switches. Right now I'm not able to initialize myFoo; I get the error "constant expression expected in initializer." Do I have to initialize it like:
struct foo myFoo[];
and change it later? If so, how do I make myFoo[] the correct length? I obviously don't have a constant available that corresponds to the desired size. Do I need to dynamically allocate this or something?
I found this similar answer but it wasn't too helpful for me - C++ a class with an array of structs, without knowing how large an array I need
struct foo* myFoo;
unsigned int myFooSize;
void initMyFoo(void)
{
myFooSize = getNumBars();
myFoo = malloc(myFooSize * sizeof(*myFoo));
for (i=0; i<myFooSize; i++) {
/* ... */
}
}
void cleanupMyFoo(void)
{
free(myFoo);
myFoo = NULL;
myFooSize = 0;
}
1 - in C99 you can use variable length arrays, which allow you to create arrays whose lengths are runtime-determined. You can also use them via compiler extensions (GCC supports them for non-C99 C and C++), but that's not a portable solution.
int someUnknownSize = 0;
/* some code that changes someUnknownSize */
struct foo myFoo[someUnknownSize];
2 - Declare a pointer that will be allocated memory at runtime with malloc or calloc.
struct foo *fooPtr = 0; /* null pointer to struct foo */
int sizeToAlloc = 0;
/* determine how much to allocate/modify sizeToAlloc */
fooPtr = malloc(sizeToAlloc * sizeof(*fooPtr));
/* do stuff with the pointer - you can treat it like you would an array using [] notation */
free(fooPtr);
I usually go for an expected maximum array size and if it's needed, just resize it:
type * a = calloc(sizeof(type),exp_array_size);
and upon pushing a new value onto the array (yeak, OK, I treat it as if it was a stack...), I check its current size against the new one:
if (current_size > max_size) {
max_size *= 2;
realloc(a,max_size*sizeof(type));
}
I still have some issues with my c code that deals with an memory mapped device.
At the moment I declare the address space for the registers I write as volatile
pointer and I write data to them as shown below:
volatile unsigned int *wr_register = (int *) 0x40000000;
volatile unsigned int *c_register = (int *) 0x40000100;
...
main{
*wr_register = 0x01234567;
*c_register = 0x01234567;
*(c_register+1) = 0x89abcdef;
}
This works more or less fine. However, I would like to have specific read and
write functions that interact with the memory mapped registers. So ideally,
it would look something like this:
const unsigned int wr_register = 0x40000000;
const unsigned int c_register = 0x40000100;
function write_REG(unsigned int address, int offset, int data)
{
(unsigned int*) (address + offset) = data;
}
main{
*write_REG(0x40000000, 0, 0x01234567);
*write_REG(0x40000100, 0, 0x01234567);
*write_REG(0x40000100, 1, 0x89abcdef);
}
I have not tried it out yet to be honest, but I am wondering if somebody could
tell me if this is a proper way to do it?
EDIT: Maybe it is of use for someone else, here I have my function and they seem to work. Many thanks for the helpful comments!
void reg_write(unsigned int address, int offset, int data)
{
*((volatile unsigned int*)address + offset) = data;
}
int reg_read(unsigned int address, int offset)
{
return(*((volatile unsigned int*)address + offset));
}
Many thanks
There are quite a few problems with your code:
I assume you meant void where you wrote function.
You should make the pointer inside the function to be volatile as well.
You should dereference the pointer before writing the data. The * should be inside the function, not at the call site (*write_REG) as it is now - that would be a compile error.
You should add the offset to the pointer, not the address. This is because an offset of 1 is meant to be the next int which could be, say, 4 bytes away, but adding it to the address will only add 1 byte.
Your corrected function should look like this:
void write_REG(unsigned int address, int offset, int data)
{
*((volatile unsigned int*)address + offset) = data;
}
and you would call it like:
write_REG(0x40000000, 0, 0x01234567);
That would be just fine IMHO. I sometimes use macros like:
#define WR_REG *(volatile unsigned int*)0x40000000
This allows the registers to be used sort of like variables:
WR_REG = 0x12345678;