By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,955 Members | 1,793 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,955 IT Pros & Developers. It's quick & easy.

assigning floating literal to void*

P: 12
if I have the following:
void *x;
const char str[]="abcdefghijklmn";

I can assign x=0x12345678;
I can assign x=str;

but how can I assign a float literal to x such that the content of x is an IEEE754 format of this literal floating point?
Sep 8 '10 #1
Share this Question
Share on Google+
18 Replies


Expert 100+
P: 2,396
So you don't want x to point at a float variable, you want the value of the pointer to coincidentally be the same as some floating-point value.

Zounds! I certainly hope C doesn't let you do that. What do you hope to accomplish?
Sep 8 '10 #2

100+
P: 1,059
You may have a player with fractional number :)

But You cant have a memory address with fractional number.
Sep 8 '10 #3

Oralloy
Expert 100+
P: 983
@hschew00,

I think this'll work. Give it a shot...

Expand|Select|Wrap|Line Numbers
  1. assert(sizeof(void *) == sizeof(float));
  2.  
  3. void *x;
  4. float f = 1.23;
  5. *((float *)(void *)&x) = f;
  6.  
  7. *((float *)(void *)&x) = 1.23f;
Sep 8 '10 #4

Oralloy
Expert 100+
P: 983
@donbock,

C lets you do many, many interesting things.

Just remember - in the end, it's all bits on the bus.

Cheers!
Sep 8 '10 #5

P: 12
@Oralloy
I realized this is the answer I will get after I posted this, and I think my original intention is not cleared to everybody. Below is a sample that what I want to achieve in embedded ARM7:

Expand|Select|Wrap|Line Numbers
  1. float fval;
  2. int ival;
  3. char sval[100];
  4.  
  5. const STR_INIT[]="ggwegweggegggwgwgw";
  6. enum
  7. {
  8.  DAT_BYTE=0,
  9.  DAT_INT,
  10.  DAT_FLOAT,
  11.  DAT_STRING
  12. };
  13.  
  14. struct PARAMETER
  15. {
  16.  void *value;
  17.  int  data_type;
  18.  void *init;
  19.  void *min;
  20.  void *max;
  21.  void *step;
  22. };
  23. const struct PARAMETER params[] =
  24. {
  25.  {
  26.   &fval,        //*value
  27.   DAT_FLOAT,    //type
  28.   10.0,         //init
  29.   0.0,          //min
  30.   100.0,        //max
  31.   0.5,          //step
  32.  },
  33.  {
  34.   &ival,       //*value
  35.   DAT_INT,     //type
  36.   10,          //init
  37.   0,           //min
  38.   100,         //max
  39.   1,           //step
  40.  },
  41.  {
  42.   sval,        //*value
  43.   DAT_STRING,  //type
  44.   STR_INIT,    //init
  45.   0,           //min
  46.   0,           //max
  47.   0,           //step
  48.  }
  49. };
  50.  
Of course the above example will generate error with visual C compiler due to the first element in params array, where you cannot assign a floating literal to a void* type.
The 2nd and 3rd elements generate warning but that is fine since the results are intended.

Base on the data_type, I can cast the <value>, <init>, <min>, <max>, and <step> to the necessary data type for data manipulation and math operation.

params is declared as const so that it uses Flash memory instead of precious RAM in ARM controller. In actual application, there are well over 200 elements in this params array and the original structure is larger than the example given above.

Another approach will be
Expand|Select|Wrap|Line Numbers
  1. struct PARAMETER
  2. {
  3.  void *value;
  4.  int  data_type;
  5.  float init;
  6.  float min;
  7.  float max;
  8.  float step;
  9. };
Then the 1st and 2nd elements yield the intended results but the compiler generates error on 3rd element because you cannot assign a char* to a float type.

Any idea to get around this?
Sep 9 '10 #6

Oralloy
Expert 100+
P: 983
@hschew00,

Where there's bits, there's hope. (At least I hope so)

The blighter here is that you want the array statically composed and implemented in ROM (flash), right?

How critical are you on memory? I know that some applications are worse than others, however you can spend considerably more memory in code (not to mention programming time) compensating for structure design, then you spend in data structures.

In this case, we're talking about an extra 800 bytes of data or so in your ROM area. I don't know if that's a deal breaker or no.

First off, can you afford an indirection array? If so, I'd recommend that you just build different structs based on the type and have done with. Or, you can go C++ and actually implement a class hierarchy. But I digress. Besides, this route may cost more than you're willing to spend. I don't know.

Expand|Select|Wrap|Line Numbers
  1. type A element0 = { ... };
  2. type B element1 = { ... };
  3. type A element2 = { ... };
  4. ...
  5. void *params[] = { &element0,
  6.                    &element1,
  7.                    &element2, ... };
Another cheap solution would be to carry an extra word or two around in the structs and have done with. Although this may double the bulk of your data, it's only 16 * 200, or 3200 bytes.

Otherwise you might try something like this and then build it out into your solution, if you find it works:
Expand|Select|Wrap|Line Numbers
  1. assert(sizeof(void *) == sizeof(float));
  2. assert(sizeof(void *) == sizeof(long));
  3.  
  4. void *x;
  5.  
  6. x = (void *)*(long *)(void *)&(1.23f);
I'm sorry I don't have a C++ compiler to test code against, I really don't want to waste your time with possibly dubious suggestions.

Of course you might be best off typing the attributes as unsigned long, so that you can treat them as simple hex values.

All that said, I wish you luck. Also, I'd like to know what your final solution is and the constraints your application is under.

Cheers!
Sep 9 '10 #7

Expert 100+
P: 2,396
C99 allows a designator to be used to initialize a union component other than the first one. The following is my initial guess at how to use this feature -- you'll probably have to play around with it before it will compile error-free. (I don't have a C99 compiler to try it out on.)
Expand|Select|Wrap|Line Numbers
  1. union V {
  2.    struct {   /* DAT_BYTE */
  3.       signed char init;
  4.       signed char min;
  5.       signed char max;
  6.       signed char step;
  7.    } bv;
  8.    struct {   /* DAT_INT */
  9.       int init;
  10.       int min;
  11.       int max;
  12.       int step;
  13.    } iv;
  14.    struct {   /* DAT_FLOAT */
  15.       float init;
  16.       float min;
  17.       float max;
  18.       float step;
  19.    } bv;
  20.    const char *sv;   /* DAT_STRING */
  21.    };
  22.  
  23. struct PARAMETER {
  24.    void * const value;
  25.    int data_type;
  26.    union V v;
  27.    };
  28.  
  29. const struct PARAMETER params[] = {
  30.    {
  31.       &fval, //*value
  32.       DAT_FLOAT, //type
  33.       {.fv = {10.0, 0.0, 100.0, 0.5}} // init,min,max,step
  34.    },
  35.    {
  36.       &ival, //*value
  37.       DAT_INT, //type
  38.       {.iv = {10, 0, 100, 1}} // init,min,max,step
  39.    },
  40.    {
  41.       sval, //*value
  42.       DAT_STRING, //type
  43.       {.sv = STR_INIT} // init
  44.    }
  45. };
-------- following added an hour later --------
I see a few ways to improve the preceding design.
  1. Move the value pointer into the union V structures. This allows us to change the type for that field from void* to a pointer to the proper type. This incidentally requires that the sv union field be changed to a structure.
  2. Add a field to the sv structure. This new field contains the size of the value buffer. This provides enough information for access code to protect itself from accessing past the end of the sv value buffer.
  3. Define each of the union V structures separately before the definition of union V. This allows access code of the following form. The benefit is that there is no possibility for a programming error in foo_int() and its peers to cause access to the wrong data_type fields of the PARAMETER.
Expand|Select|Wrap|Line Numbers
  1. foo_int(const struct iv *pi);
  2.  
  3. foo_parameter(const struct PARAMETER *pp) {
  4.    switch (pp->data_type) {
  5.       case DAT_INT:
  6.          foo_int(&pp->v.iv);
  7.          break;
  8.       ...
  9.    }
  10. }
Sep 9 '10 #8

P: 12
Thanks Donbock. That looks like it may work. I will try that out and post the result. You mentioned C99 has to be used instead of ANSI C (C90??), I may have a problem with the compiler that I got from Keil. I will check that out.
Sep 9 '10 #9

Oralloy
Expert 100+
P: 983
Don,

Ask an amature (me) get one answer; ask a master (you), get the right answer.

Thanks,
Oralloy!
Sep 9 '10 #10

P: 12
@Oralloy,
Your solution of different struct for different data type can be another option too. The original structure used in my application is 48bytes instead of 16bytes, moreover, the controller that I used has 16k of RAM only.
Sep 9 '10 #11

Oralloy
Expert 100+
P: 983
@hschew00,

I know what you're saying. I'm just amazed at the ways in which our tools are evolving to solve our real-world problems. For instance, the selective initializers in C99 as an alternative to overloaded constructors in C++.

The C99 solution is elegant, and very good for statically composing data. The problem with C++ constructors is, of course, that they're dynamic.

I just wish I'd have had selective initialization when I was working on a Rabbit processor building a controller for a destktop instrument in the mid 1990's. It would have made a few of my very interesting (spelled ugly) set-up problems in command and parameter parsing just disappear.

One of the things that interests me is that you've got a problem which fits quite well into the object oriented inheritence model, but which you can't use the (in my mind) appropriate tools. So you're stuck open coding (and maintaining) an objective solution, when you should be solving your problem.

I guess I'm just grousing, because we (as the embedded community) haven't really solved the static initialization problem very well, even as our problems become more complex. We don't seem to deal with dynamic memory very well, either. I just growl at C++ code where all objects must be constructed at program start, and never deleted, although dynamically reusing them is ok. Talk about foolish and frustrating use of the language. Basically writing memory managers that manage fixed pools of objects, not memory. Just because folks are afraid that there might be some magic combination of allocations/deallocations that eats all memory and causes failure. So, instead we have multitude problems with stale references and object pool starvation.

Don has the right of it. Use an enum of separately declared classes, and then treat each class as distinct in your code by using strongly typed pointers. Then you will hopefully avoid all the problems which arise from invalid enum references in your code.

Luck!
Sep 9 '10 #12

Expert 100+
P: 2,396
You mentioned C99 has to be used instead of ANSI C (C90??) ...
  • In the beginning, the C language was bestowed by Brian Kernighan and Dennis Ritchie. Now we look back on those halcyon days and call that "K&R C".
  • As time passed, compiler vendors added sundry variations and enhancements.
  • C was first standardized by ANSI in 1989; that same standard was adopted by ISO in 1990. This first standard C is variously referred to as C89 or C90.
  • The ISO standard for C was revised in 1999. This second standard C is referred to as C99.
  • Minor clarifications, corrigendums, and changes have occurred between C90 and C99, but I don't know what names people use for them.
Sep 9 '10 #13

Expert 100+
P: 2,396
I guess I'm just grousing, because we (as the embedded community) haven't really solved the static initialization problem very well, even as our problems become more complex.
I've used four strategies for complicated static initialization in my embedded C projects.
  1. Suck it up and do it all by hand. Error-prone, but I can write the initialize code immediately.
  2. Write macros that hide some of the complications. Unfortunately, this only works for not-very complicated initialization.
  3. Implement the initialization with inline tcl code by making use of a generic tcl preprocessor called cpdq that I found in a 1998 Dr. Dobbs article.
  4. Write my own custom preprocessor in perl. Two input files: an invariant perl program I developed, and a specific initialization file that takes the form of perl code. The invariant program is designed to allow the specific initialization to look as much like the logical model of the initialization as possible.
The tcl and cpdq preprocessors have allowed me to add redundancy to collections of static structures in order to improve execution speed without risking inconsistencies in the redundant data.
Sep 9 '10 #14

P: 12
Don,
I think Visual C 6.0 doesn't like the initialization of union part. i.e.,{.iv = {10, 0, 100, 1}}, same with my Keil Compiler. How would you initialize a static object of a union of different structure types in ANSI C?
Sep 9 '10 #15

Oralloy
Expert 100+
P: 983
@hschew00

You might try something really, really ugly - a large container class with sequential instances of the specific classes (assuming all they are the same size),
then simply taking the address of the container and treating it as an array...

Expand|Select|Wrap|Line Numbers
  1. struct A{...};
  2. struct B{...};
  3. struct C{...};
  4.  
  5. struct ugly{
  6.   struct A first;
  7.   struct B second;
  8.   struct C third;
  9.   struct A fourth;
  10.   ...
  11. } myArray = { ... };
  12.  
  13. union
  14. {
  15.   struct A a;
  16.   struct B b;
  17.   struct C c;
  18. }
  19. * myArrayPointer = (void *)&myArray;
  20.  
Or is this just too ugly to contemplate?
Sep 9 '10 #16

P: 12
@Oralloy,
Your solution is way above me. After googling around, realized that ANSI C does not support static initialization for Union, that is a shame. May be I have to give up this approach totally. Thanks to you and Don anyway.
Sep 9 '10 #17

Oralloy
Expert 100+
P: 983
@hschew00,

My latest solution was to build a monolithic struct with each of the parameter specifications laid out in turn.

Then, I'd point a "parameter pointer" at the structure, and use the memory like it was an array.

Complete and total abuse of the C language.

The idea was to use the containing structure to force the sequential memory layout of each parameter object. Since they are all the same size, they should be laid out correctly, as if in an array.

As I said, complete abuse of the C language. But it should work.

Otherwise you're stuck using ugly casts like the one I wrote in the second example in post #7.

Good luck, man.

Cheers!
Sep 9 '10 #18

Expert 100+
P: 2,396
After googling around, realized that ANSI C does not support static initialization for Union, that is a shame.
Not so! It is true that K&R C does not support the use of an initializer with a union type. However, C90 mandated that initializers had to be supported for union types; unfortunately, such initializers have to correspond to only the first element in the union. Then C99 mandated that designators be supported in union initializers so that the initializer value can correspond to any element of the union.

Check your compiler documentation. It should tell you whether or not it is C99-compliant. Look carefully, there may be a option switch that you can throw to activate/deactivate C99 compliance.
Sep 9 '10 #19

Post your reply

Sign in to post your reply or Sign up for a free account.