Variable casting...

Go To Last Post
64 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everybody,
I'm not an experienced C programmer, so I know this is a very simple question for this forum, but I couldn't found a solution yet.

I have this code:

char post_screen[7]="   ";                
char num[10]="0123456789"; 
char   alfa[37]="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 
appSendLcdMsg(post_screen);

The display (appSendLcdMsg function) start to show up all the numbers and letters, I think the reason was that "post_screen" was taken like a pointer and not like a string...right?
How can I do that casting?
I found some solutions on the web but no success"¦
Thanks for the help!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's something else going on there, as the string array will decompose automatically into a (char*) when the name is passed into the function. This sounds more like a buffer overrun that's causing the LCD write routine to access the memory past the desired array. Is the code you posted exactly how it appears in your application? What does the appSendLcdMsg() function look like?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, the code is not exactly as I posted, this is extracted from ATMEL's bitcloud.
appSendLcdMsg() is a "redefinition" for BSP_SendLcdCmd()this is the code...

void BSP_SendLcdMsg(const char *str)
{
  SipcFramePart_t parts[] =
  {
      {&(uint8_t){SIPC_CMD_ID_MSG}, 1},
      {(uint8_t*)str, strlen(str)},
  };
  bspSipcSendFrameByParts(parts, sizeof(parts)/sizeof(parts[0]));
}

This "char" is later transmitted to another micro, ATMEGA3290, it's part of the RAVEN board architecture....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
char num[10]="0123456789";

Wrong, [11] !!

But I don't see the point in dimensioning strings that will be auto-dimensioned anyway. Remove all the numbers from your [] above and try again.

Last Edited: Thu. May 19, 2011 - 01:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you by chance modify any element of post_screen between its definition and the call to appSendLcdMsg()? Maybe the zero at the end of the string got overwritten?

Einstein was right: "Two things are unlimited: the universe and the human stupidity. But i'm not quite sure about the former..."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson was right...after dimension the array (nº of elements)+1 start working fine...
Thanks to all of you people.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

char num[10]="0123456789";

Wrong, [11] !!

But I don't see the point in dimensioning strings that will be auto-dimensioned anyway.

There is one particular case when explicit dimensioning is justified: when you don't want the trailing zero to be there.

But this is not troyka's case.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since no-one has made it explicitly clear, what Cliff is suggesting (to avoid erroneous number of element being reserved) is:

char num[]="0123456789";

Notice the absense of any explicit mention of number of elements, troyka!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

noted the error... thanks!
One more question:

post_screen[0]="2-     ";
appSendLcdMsg(post_screen);

this code gave me the next warning:

Quote:
src/example.c:134: warning: assignment makes integer from pointer without a cast

If I start the string with a non numeric char, the warning disappears…How can I solve that warning?(besides adding a space of course)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

post_screen[0]="2- ";

try:

strcpy(post_screen, "2-     ");

post_screen[0] is a single character. You cannot assign "anything" to it as that is a string. The assignment will try to set the address of the string ("pointer") into that single array element. That's why you get the warning about making an integer from a pointer. What would be vaild is:

post_screen[0 = 'A';

Because 'A' is the single character A. But to assign strings in this way you'd have to assign [0], [1], and so on separately.

You may want to get yourself a book on C as you are making some pretty basic mistakes in your understanding about how C uses strings. I wonder if perhaps you have used some higher level language previously?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
[...]you are making some pretty basic mistakes in your understanding about how C uses strings. I wonder if perhaps you have used some higher level language previously?
How on earth could command of any high level language be even remotely related with the ugly hackish mockup C uses instead of strings?

JW (The C-Hater)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wek wrote:
How on earth could command of any high level language be even remotely related with the ugly hackish mockup C uses instead of strings?

I would think that would be quite easy. If one is used to using "real" strings in a HLL, things like the lack of assignment ( the need for strcpy and related ), and the requirement that the programmer deal with storage for the end of string character ( on non-automatic strings ) could seem very strange.

I for one do not ( mostly because of my work with C++, Python and Java ) even consider C to have "strings"... I am quite careful to remember that they are simply arrays of characters ( or pointers to characters ), for reasons including those above. That there is no fully-functional, first-class, string data type is fine for C, it does not limit its ability; but it does make it very different than most of the languages that one might learn on at this point.

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Martin pretty much made the point I had in mind.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

You may want to get yourself a book on C as you are making some pretty basic mistakes in your understanding about how C uses strings. I wonder if perhaps you have used some higher level language previously?

This is my first "HLL" (no intention to start a debate again about "the level") :)
I'm now making experience on C, I have several books, but some errors are hard to solve if you are a "newbie", even looking on internet.
Here is another one:

on file example1.c (extract):

char	PLACE[]="       ";

on file example2.c (extract)

	
extern char	PLACE;
char	post_screen[]="1-     ";

strcpy(PLACE, post_screen);
BSP_SendLcdMsg(PLACE);


src/WSNVisualizer.c:81: warning: passing argument 1 of 'BSP_SendLcdMsg' makes pointer from integer without a cast

If I use BSP_SendLcdMsg(&PLACE); there is no warning, as the function is expecting a pointer.
But nothing is displayed.
If I use BSP_SendLcdMsg("TEXT"); is working fine.

void BSP_SendLcdMsg(const char *str)
{
  SipcFramePart_t parts[] =
  {
      {&(uint8_t){SIPC_CMD_ID_MSG}, 1},
      {(uint8_t*)str, strlen(str)},
  };
  bspSipcSendFrameByParts(parts, sizeof(parts)/sizeof(parts[0]));
} 

Is there any error on code?
Thanks in advance!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

troyka wrote:
on file example1.c (extract):

char	PLACE[]="       ";

So PLACE is an array of char.
troyka wrote:
on file example2.c (extract)

extern char	PLACE;

But here you tell the compiler that PLACE is only a single char (not an array).

Change it to:

extern char	PLACE[];

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Problem solved.
Thanks for remarking me that error.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

and yet another string problem, hope this is the last one...
on file one.c :

char PLACE[]="1234567";
appMessage.data.meshbean.PLACE=PLACE;   <- Here is the prblm

on file two.h is defined the struct.:

extern char   PLACE[]; 

BEGIN_PACK
typedef struct
{
  uint8_t     messageType;
  uint8_t     nodeType;
.
.
  struct {
    int32_t  battery;
    int32_t  temperature;
    int32_t  light;
    char     PLACE;
  } meshbean;
} PACK AppMessage_t;

I also tried using strncpy but always have the "warning: assignment makes integer from pointer without a cast"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In your struct you have declared PLACE to be a single character, while in your function's code PLACE is an array of characters (specifically, a pointer to an array in memory).

You can either:
1) Make "char PLACE" a "char* PLACE" in your "meshbean" struct, so that the pointer to the array is copied
2) Make "char PLACE" a "char PLACE[N]" in your "meshbean" struct, where "N" is a constant giving the largest possible array length you need to store

The two options don't give the same results; in the first case, your struct will simply contain a two-byte pointer to the string array somewhere in memory. If that memory becomes invalid for some reason (say, your local string array goes out of scope) the string in the struct will become corrupt.

In the second option, you are physically copying the string contents into an array inside the struct, which will consume more space but won't suffer from corruption when the original array goes out of scope.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

2) Make "char PLACE" a "char PLACE[N]" in your "meshbean" struct, where "N" is a constant giving the largest possible array length you need to store


In which case the = assignment operator is not going to work. You need to use memcpy()/strcpy().

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So the problem was that PLACE was not defined as a string in the struct and strcpy cannot copy a string to a char.... that's why the command was not working for me....
I will try that and hope the communication between devices occur
Thanks for the help!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to understand the difference between a char and an array of char. The latter also has a base address (the address of element [0]) which is a pointer to the array.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everybody, I'm trying to transmit via uart a simple string of 3 numbers using the next code. I think I'm having a problem telling the compiler the "type" of data in the pointer, however, he finds out by himself, but I still have the warnig down there.
(couldn't test the code yet)
Can someone please give me some help.

uint8_t	frame_1[]= {0x01,0x02,0x03};
send_frame(&frame_1);

void send_frame(uint8_t *FRAME){  <<<--- error line
	uint8_t cont = 0;
	uint8_t x =0;
	for (x=0; x<5; x++){
			cont=FRAME[x];
			while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
			UDR0 = cont;
	}
}

And the warning (and almost error):
"Almost" because the second time I do "compile", no errors founds, and the error still permit generate the hex file...

Quote:
passing argument 1 of 'send_frame' from incompatible pointer type
expected 'uint8_t *' but argument is of type 'uint8_t (*)[3]'

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frame_1 is an array. To pass the address of an array, just send the name:

send_frame(frame_1);

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
frame_1 is an array
... which means, that it is a pointer already.

The reason is, that there are in fact no arrays implemented in C. Instead, a kludge is used, where the array-like notation in declaration causes an appropriate space in memory to be created, and the name of array is considered to be a pointer. The array-member-access-like notation is then simply converted to that pointer being incremented by the array offset and dereferenced, i.e.

frame_1[2]

is compiled as if it would be

*(frame_1 + 2)

This kludge also explains why the "arrays" in C are invariably indexed from 0.

You should get a reading of some good C book.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
... which means, that it is a pointer already.
No, a pointer is a variable whose value is an address. The name of an array is taken by the compiler to be the address of the first element of an array, but it by itself is not a variable (you can not assign a value to it). Though they can be used in most instances in identical ways, there are instances where they most definitely are NOT the same.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Quote:
... which means, that it is a pointer already.
No, a pointer is a variable whose value is an address. The name of an array is taken by the compiler to be the address of the first element of an array, but it by itself is not a variable (you can not assign a value to it).

True. I tried to formulate it as briefly as possible. The complete wording is in C99 6.3.2.1#3, and is possibly even more confusing.
Koshchi wrote:
Though they can be used in most instances in identical ways, there are instances where they most definitely are NOT the same.
There's only one notable exemption, and that's when the sizeof operator is applied to the array name.

(Said C99 6.3.2.1#3 mentions the & operator as the other exception, but that's exactly what leads to the warning above - this was obviously added as a kludge on kludge to more closely mimic behaviour of arrays in high level languages; otherwise it would lead straight to an error as you cannot apply & on an expression which is not an l-value).

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

There's only one notable exemption, and that's when the sizeof operator is applied to the array name.

There is also the exeption that you can not assign a value to the array variable as such (as mentioned above).

I hacked a small demo, since the subject amuses me :wink:

int a1[] = {1,2,3};
int a2[] = {4,5,6};

int * p1;

int main(int argc, char* argv[])
{
    // This WON'T work (build error)
    a1 = a2;

    // This WILL work - make a pointer point to an array
    p1 = a1;

    // This will work - de-reference the array variable as a pointer and 
    // use as l-value
    *a1 = 42;       // Assign new value to a1[0]

    // This will also work - de-reference the array variable as a pointer,
    // use it in pointer arithmetics and use the result as an l-value
    *(a1+2) = 55;   // Assign new value to a1[2]
    // The code above is equivalet to  
    a1[2] = 55;

    // This will work - pointer arithmetics used as an l-value
    *(p1+2) = 99;    // Assign new value to a1[2]
    // This will also work - pointer used with "array notation"
    // Funtionally equivalent to the previous example
    p1[2] = 99;     // Assign new value to a1[2]

	return 0;
}

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks all for that pointer class.
All that left me two questions:
1) in my previous error= &frame_1, frame 1 already contain an address, so what is the result of "the address of the address"??? I mean &frame_1. what was the compiler translating there?? Is that the case of pointers to pointers?

2) my other question is about l-value mentioned before several times. what does it mean?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) Why not write a short example and use your UART output routines to see the result ;-)

2) Left hand value - the thing on the left side of the '='

EDIT: for (1) I tried this:

#include 

uint8_t   frame_1[]= {0x01,0x02,0x03}; 

int main(void){
 OCR1A = frame_1;
 OCR1A = &frame_1;
 OCR1A = &frame_1[0];
}

The code it generated was:

 OCR1A = frame_1;
  82:	80 e6       	ldi	r24, 0x60	; 96
  84:	90 e0       	ldi	r25, 0x00	; 0
  86:	9b bd       	out	0x2b, r25	; 43
  88:	8a bd       	out	0x2a, r24	; 42
 OCR1A = &frame_1;
  8a:	9b bd       	out	0x2b, r25	; 43
  8c:	8a bd       	out	0x2a, r24	; 42
 OCR1A = &frame_1[0];
  8e:	9b bd       	out	0x2b, r25	; 43
  90:	8a bd       	out	0x2a, r24	; 42

So the same value (0x0060) used in all cases. Also from the .map file:

 .data          0x00800060        0x3 test.o
                0x00800060                frame_1

(the 0x800000 offset in this is what avr-gcc uses to offset SRAM address 0 from clash address 0 - so it's really 0x0060 in SRAM)).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

l-value mentioned before several times. what does it mean?

http://en.wikipedia.org/wiki/Value_(computer_science)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Koshchi wrote:
Quote:
... which means, that it is a pointer already.
No, a pointer is a variable whose value is an address. The name of an array is taken by the compiler to be the address of the first element of an array, but it by itself is not a variable (you can not assign a value to it).

True. I tried to formulate it as briefly as possible. The complete wording is in C99 6.3.2.1#3, and is possibly even more confusing.

Re "Alice in Wonderland", Lewis Carroll, from http://www.alice-in-wonderland.n...

Quote:
Then there is the passage in which the White Knight proposes to comfort Alice by singing her a song:

"Is it very long?" Alice asked, for she had heard a good deal of poetry that day.

"It's long," said the Knight, "but it's very, very beautiful. Everybody that hears me sing it--either it brings the tears into their eyes, or else--"

"Or else what?" said Alice, for the Knight had made a sudden pause.

"Or else it doesn't, you know. The name of the song is called 'Haddock's Eyes'."

"Oh, that's the name of the song, is it?" Alice said, trying to feel interested.

"No, you don't understand," the Knight said, looking a little vexed. "That's what the name is called. The name really is 'The Aged Aged Man'."

"Then I ought to have said 'That's what the song is called?'" Alice corrected herself.

"No, you oughtn't: that's quite another thing! The song is called 'Ways and Means': but that's only what it's called, you know!"

"Well, what is the song, then?" said Alice, who was by this time completely bewildered.

"I was coming to that," the Knight said. "The song really is 'A-sitting on a Gate': and the tune's my own invention."

Now that is formal logic served up with an apple in its mouth! Those familiar with programming computers in higher-level languages will see there a clear delineation of the difference between a datum, the symbolic name of that datum, the address at which the datum is stored, and the symbolic name of that address. ...

;) Enjoy.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks everybody for let me understand a little better pointers and the use of the "disassembler view", I never figure out that could be used in that way, maybe because this was the first time I use that kind of view, was helpful to illustrate.
And interesting too, the article of the pointer to the pointer to the pointer to Alicia's song!
Regards.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

troyka wrote:
1) in my previous error= &frame_1, frame 1 already contain an address, so what is the result of "the address of the address"??? I mean &frame_1. what was the compiler translating there?? Is that the case of pointers to pointers?
No, and it's thanks to the second exception to the "array name is converted to pointer" rule in said C99 article, "when subject to & operator". I.e. it does what it's expected to do - it returns pointer to the first element of the array - and as I explained in the bracket above, that's probably an intentional "undo" of the kludge to obtain a behaviour the programmers already knew from real programming languages.

troyka wrote:
2) my other question is about l-value mentioned before several times. what does it mean?
Now this has been already answered above, but if you go to the mentioned article in C99, incidentally there's a footprint explaining this, which is put down in a remarkably readable style (compared to the rest of C99).

---
Lee, that was hillarious; it's even more funny when one realizes how Alice was meant by its author...

---
Johan, for the *real fun*, you should add

int w = 2[a1];

to your example.

Jan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jan, that is my usual rant (a parto of which you repeated above) about "accessing array elements with indexing notation". Here's the short version:

a[i]

is just syntactic sugar for

*(a+i)

and since the operands of the + operator are commutative you could just as well do

*(i+a)

which also means that what follows is completely equivalent to the first code

i[a]

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

i[a]

There is one constraint to the [] games, though: exactly one of the operands has to be a pointer (or sort of).

Now, at this point we all are surely ready for some whip-up, adding also the second kludge which in C replaces strings, namely string literals (the following example is taken directly from the Derek Jones book):

extern int arr[10];

(arr+2)[3]=4["abcdefg"];

It took me around 10 years to understand how such absurd syntax could come around (OK I did also a few other things besides thinking about the quirks of C during those 10 years :-) ). No wonder I am not ready to accept the post-increment postfix operator to that language... ;-)

Jan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
(arr+2)[3]=4["abcdefg"];

LOL!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another question:
If I have this code:

uint8_t	ARRAY_1[]= {0x01,0x03,0x86,0x01,0x78,0x52};
uint16_t value;

Is there any way to load two consecutive 8 bit on the 16 bit variable?
If I do value=ARRAY_1[1];
value = 0x0003 and not 0x0386 (I would like this last one)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The "as if it would be a real programming lanugage" way:

value = ARRAY_1[1] * 256 + ARRAY_1[2];

The "look bro I am a kewl C coder" way:

value = *(uint16_t *)&ARRAY_1[1];

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks JW, the first way open my eyes a little more with C programming, the second way put in clear that I'm not even closer a cool C coder.
Could you explain the last one a little more please?
thanks!

pd. It works, but it tooks the array inverted, if I try to load 0386 that code loads 8603...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a prime example of pointer abuse in C. Strictly reading the standard this is not guaranteed to work at all; but it's such a popular construct that I doubt any compiler is brave enough to spoil the fun.

value = *(uint16_t *)&ARRAY_1[1]; 

You read it from right to left: the & operator takes the address of ARRAY_1[1] so that now we have a value which is of type "pointer to uint8_t" and points to ARRAY_1[1]; (uint16_t *) casts that (changes its type) into a pointer to uint16_t; and finally the * dereferences that pointer i.e. tells the compiler to look at the variable of the target type (here of type uint16_t) at the given address.

JW

PS. The "does not work" shows one of the reasons why this should not be used - it depends on the endianness of the compiler.

PS2. The reason why the "kewl C coders" are in liking of constructions like these is that they believe that cramming in a lot of functionality in a single line and avoiding arithmetics would result in a more optimal binary. They can't be more wrong, though.

Last Edited: Sat. Oct 15, 2011 - 06:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

pd. It works, but it tooks the array inverted, if I try to load 0386 that code loads 8603...

Google "Little Endian"

EDIT: actually this covers both:

http://en.wikipedia.org/wiki/End...

but note that the AVR is naturally little endian and most compilers (including GCC) therefore follow that lead.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clear as crystal.
Thank you JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW, as Jan says the first form is preferable as it works on all CPUs and with all C compilers as it doesn't care about endianness. Just one possible modification (though a good compiler will do the same for both) but:

value = (ARRAY_1[1] >> 8) + ARRAY_1[2]; 

In theory >>8 and *256 are the same thing but you never know how smart the code generator is going to be and anything that helps it produce optimal code is probably a good idea.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

pd. It works, but it tooks the array inverted, if I try to load 0386 that code loads 8603...

Google "Little Endian"

EDIT: actually this covers both:

http://en.wikipedia.org/wiki/End...

but note that the AVR is naturally little endian and most compilers (including GCC) therefore follow that lead.

So, you are telling me that I'm upside down when I store the array? (or the way I thought It must be stored?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No there's no doubt about how :

uint8_t   ARRAY_1[]= {0x01,0x03,0x86,0x01,0x78,0x52};

is stored in memory. It will be:

ARRAY_1: .db 0x01
         .db 0x03
         .db 0x86
         .db 0x01
         .db 0x78
         .db 0x52

However suppose you then use:

uint16_t * ptr;
ptr = &ARRAY_1[2];
uint16_t val;
val = *ptr;

Then the pointer to 16 bit will be pointing at the byte pair 0x86, 0x01. But there are two ways it could be interpreted. It's either 0x86 as the high byte and 0x01 as the low byte. This is big endian (natural reading order) and val would hold 0x8601. Otherwise it could be interpreted as the first byte (0x86) being the low byte and the next byte (0x01) being the high byte. This is little endian and val would hold 0x0186. This is what would happen with GCC on the AVR (and probably all other AVR C compilers).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Just one possible modification (though a good compiler will do the same for both) but:

value = (ARRAY_1[1] >> 8) + ARRAY_1[2]; 

In theory >>8 and *256 are the same thing but you never know how smart the code generator is going to be and anything that helps it produce optimal code is probably a good idea.

<<8 ;-)

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I got the "chevrons" right anyway! :lol:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Strictly reading the standard this is not guaranteed to work at all
In what way is it "not guaranteed to work"? Certainly taking an address of an array element will work. Casting a uint8_t pointer to a uint16_t pointer will work (though it is up to the programmer to ensure that the two bytes pointed to are in the confines of the array). And taking the value of what a uint16_t pointer points to is perfectly valid (though again the programmer must ensure that the byte order of those two bytes makes sense).

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The devil is, as they say, in the details. There are subtle ways in which this monstrosity is akin to fail. Endianness is one of the less harmful ones, there are more.

Consider C99 6.3.2.3#7 (which is the paragraph governing pointer conversions, thus also casts):

Quote:
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.
Yes, the dreaded "undefined behaviour" (3.4.3), which includes compile-time and run-time error and quietly generated wrong result.

This is simple to understand once you realize that there are architectures which require that non-byte values must be placed on properly aligned addresses, as that simplifies memory controller logic.

For example, the Intel '196 16-bit microcontroller requires that words are placed on even addresses. If you have an odd address in a register and perform an indirect word read or write, the result is surprising from point of view of the C programmer (but fully comprehensible for anybody who ever designed a memory controller): the word is read/written from/to an address one less than what's in the address register.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Yes, the dreaded "undefined behaviour" (3.4.3), which includes compile-time and run-time error and quietly generated wrong result.

But all alignment on the AVR is 8bit - how could it ever be misaligned?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

Yes, the dreaded "undefined behaviour" (3.4.3), which includes compile-time and run-time error and quietly generated wrong result.

But all alignment on the AVR is 8bit - how could it ever be misaligned?
So, if I understand it correctly, you say that it may be a principially wrong construct, but as it incidentally works on AVR, or even on *most* of the architectures, it's then OK to use it?

This is exactly my main problem with C.

Jan

Pages