assigning floating literal to void*

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • hschew00
    New Member
    • Aug 2009
    • 12

    #1

    assigning floating literal to void*

    if I have the following:
    void *x;
    const char str[]="abcdefghijklm n";

    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?
  • donbock
    Recognized Expert Top Contributor
    • Mar 2008
    • 2427

    #2
    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?

    Comment

    • johny10151981
      Top Contributor
      • Jan 2010
      • 1059

      #3
      You may have a player with fractional number :)

      But You cant have a memory address with fractional number.

      Comment

      • Oralloy
        Recognized Expert Contributor
        • Jun 2010
        • 988

        #4
        @hschew00,

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

        Code:
        assert(sizeof(void *) == sizeof(float));
        
        void *x;
        float f = 1.23;
        *((float *)(void *)&x) = f;
        
        *((float *)(void *)&x) = 1.23f;
        Last edited by Oralloy; Sep 8 '10, 11:57 PM. Reason: enhanced the example.

        Comment

        • Oralloy
          Recognized Expert Contributor
          • Jun 2010
          • 988

          #5
          @donbock,

          C lets you do many, many interesting things.

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

          Cheers!

          Comment

          • hschew00
            New Member
            • Aug 2009
            • 12

            #6
            @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:

            Code:
            float fval;
            int ival;
            char sval[100];
             
            const STR_INIT[]="ggwegweggegggwgwgw";
            enum
            {
             DAT_BYTE=0,
             DAT_INT,
             DAT_FLOAT,
             DAT_STRING
            };
             
            struct PARAMETER
            {
             void *value;
             int  data_type;
             void *init;
             void *min;
             void *max;
             void *step;
            };
            const struct PARAMETER params[] =
            {
             {
              &fval,        //*value
              DAT_FLOAT,    //type
              10.0,         //init
              0.0,          //min
              100.0,        //max
              0.5,          //step
             },
             {
              &ival,       //*value
              DAT_INT,     //type
              10,          //init
              0,           //min
              100,         //max
              1,           //step
             },
             {
              sval,        //*value
              DAT_STRING,  //type
              STR_INIT,    //init
              0,           //min
              0,           //max
              0,           //step
             }
            };
            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
            Code:
            struct PARAMETER
            {
             void *value;
             int  data_type;
             float init;
             float min;
             float max;
             float step;
            };
            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?
            Last edited by Niheel; Sep 9 '10, 03:06 AM. Reason: please use code tags to display code

            Comment

            • Oralloy
              Recognized Expert Contributor
              • Jun 2010
              • 988

              #7
              @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.

              Code:
              type A element0 = { ... };
              type B element1 = { ... };
              type A element2 = { ... };
              ...
              void *params[] = { &element0,
                                 &element1,
                                 &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:
              Code:
              assert(sizeof(void *) == sizeof(float));
              assert(sizeof(void *) == sizeof(long));
              
              void *x;
              
              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!

              Comment

              • donbock
                Recognized Expert Top Contributor
                • Mar 2008
                • 2427

                #8
                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.)
                Code:
                union V {
                   struct {   /* DAT_BYTE */
                      signed char init;
                      signed char min;
                      signed char max;
                      signed char step;
                   } bv;
                   struct {   /* DAT_INT */
                      int init;
                      int min;
                      int max;
                      int step;
                   } iv;
                   struct {   /* DAT_FLOAT */
                      float init;
                      float min;
                      float max;
                      float step;
                   } bv;
                   const char *sv;   /* DAT_STRING */
                   };
                
                struct PARAMETER {
                   void * const value;
                   int data_type;
                   union V v;
                   };
                
                const struct PARAMETER params[] = {
                   {
                      &fval, //*value
                      DAT_FLOAT, //type
                      {.fv = {10.0, 0.0, 100.0, 0.5}} // init,min,max,step
                   },
                   {
                      &ival, //*value
                      DAT_INT, //type
                      {.iv = {10, 0, 100, 1}} // init,min,max,step
                   },
                   {
                      sval, //*value
                      DAT_STRING, //type
                      {.sv = STR_INIT} // init
                   }
                };
                -------- 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.

                Code:
                foo_int(const struct iv *pi);
                
                foo_parameter(const struct PARAMETER *pp) {
                   switch (pp->data_type) {
                      case DAT_INT:
                         foo_int(&pp->v.iv);
                         break;
                      ...
                   }
                }

                Comment

                • hschew00
                  New Member
                  • Aug 2009
                  • 12

                  #9
                  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.

                  Comment

                  • Oralloy
                    Recognized Expert Contributor
                    • Jun 2010
                    • 988

                    #10
                    Don,

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

                    Thanks,
                    Oralloy!

                    Comment

                    • hschew00
                      New Member
                      • Aug 2009
                      • 12

                      #11
                      @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.

                      Comment

                      • Oralloy
                        Recognized Expert Contributor
                        • Jun 2010
                        • 988

                        #12
                        @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!

                        Comment

                        • donbock
                          Recognized Expert Top Contributor
                          • Mar 2008
                          • 2427

                          #13
                          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.

                          Comment

                          • donbock
                            Recognized Expert Top Contributor
                            • Mar 2008
                            • 2427

                            #14
                            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.

                            Comment

                            • hschew00
                              New Member
                              • Aug 2009
                              • 12

                              #15
                              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?

                              Comment

                              Working...