3

I have a float variable , which needs to be passed as uint8_t to the function .

How do I convert back to float original value .

Code:

bool SetAnalog(uint8_t number, float voltage, MessagePriority priority, Callback clbck)
{
    uint8_t args[2];
    args[0] = number;
    memcpy(&(args[1]),&voltage,sizeof(float));

    PTCLoopOutMessage* message = parent()->GetLoopOutMessage(this,
                                                             this->address(),
                                                             _OutputVoltage,
                                                             "DACVoltage",
                                                             args,
                                                             sizeof(args),
                                                             Device,
                                                             priority);
    message->SetCallback(clbck);

    return ProcessOutMessage(message);
}

I try to get back the float original value from uint8_t array and need to assign to probe[channel]

uint8_t channel = message->GetOutMessage()->GetData()->data[0];
unsigned char* value = &message->GetOutMessage()->GetData()->data[1];
memcpy(&__output.output.probe[channel].dac, value, sizeof(float));

I always get value as 0,

Please Help

boleto
  • 1,149
  • 1
  • 22
  • 32
user2746930
  • 139
  • 1
  • 11
  • 1
    Oh wait... 'DACVoltage' - what exactly is GetLoopOutMessage() requiring in that array?? – Martin James Sep 04 '13 at 13:05
  • virtual PTCLoopOutMessage* GetLoopOutMessage(PTCHardware* source, uint8_t address,uint8_t command, const char* commandString, const uint8_t* data, size_t dataLength, PTCMessageType messageType, PTCMessagePriority priority) = 0; – user2746930 Sep 04 '13 at 13:57

2 Answers2

7

You have undefined behavior in your code. A float is normally four bytes long, while uint8_t is a single byte. So you overwrite your array with at least three bytes.

Then when you pass it in the GetLoopOutMessage you only pass the actual array (which is two bytes), so the floating point number is now missing the majority of its data.

You might want to use e.g.

uint8_t args[1 + sizeof(float)];

If the GetLoopOutMessage doesn't copy the data you pass to it, then you have another case of undefined behavior, namely passing around a pointer to a local variable. When the SetAnalog function returns, the space in memory where local variables are stored is reused by the next function call. This means that the args array no longer exists in memory, and where it used to be there may now be other data.

To solve this you either should make the args array static, make it global (really not recommended) or to dynamically allocate it on the heap:

uint8_t* args = new uint8_t[1 + sizeof(float)];

Don't forget to delete this pointer once your done with it (i.e. when you retrieved the data).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks a lot, but still the value holds 0 in spite of changing to args[5]. – user2746930 Sep 04 '13 at 13:04
  • I've never seen any 'DAC' hardware stuff that takes a float as an argument, either directly or as byte-copied into an array. – Martin James Sep 04 '13 at 13:08
  • args array holds the value of args[5]={0,0,0,64,65}, when the probe number is 0 , and the voltage is 12. – user2746930 Sep 04 '13 at 13:08
  • @user2746930 After a quick test my self, the `float` number `12.0` seems to be the byte sequence `0 0 64 65`, so the data is correct. It may however be another problem, actually another case of undefined behavior. Please see my updated answer. – Some programmer dude Sep 04 '13 at 14:33
0

Try it like this:

struct MyArgs {
  uint8_t channel;
  float voltage;
} *args = new MyArgs();
args->channel = number;
args->voltage = voltage;

Then pass it like this:

....GetLoopOutMessage(....., (uint8_t *)args, sizeof(*args), ....)

And read the data out like this:

struct MyArgs {
  uint8_t channel;
  float voltage;
} *args = (struct MyArgs *)message->GetOutMessage()->GetData()->data;

uint8_t channel = args->channel;
__output.output.probe[channel].dac = args->voltage;

delete args;

Note that I've used new/delete here, not local stack storage, because you appear to be using the data in a callback, so I'm guessing your data has been overwritten (with zero, as it happens) before you get to read it.


If new/delete is inappropriate (GetLoopOutMessage makes a copy of the data), then do it like this:

struct {
  uint8_t channel;
  float voltage;
} args = {number, voltage};

Then pass it like this:

....GetLoopOutMessage(....., (uint8_t *)&args, sizeof(args), ....)

And read the data out like this:

struct mydata {
  uint8_t channel;
  float voltage;
} *args = (struct mydata *)message->GetOutMessage()->GetData()->data;

uint8_t channel = args->channel;
__output.output.probe[channel].dac = args->voltage;
ams
  • 24,923
  • 4
  • 54
  • 75
  • This may work, but if it expects the float right after the uint8 then padding is going to be a problem unless the struct is packed. – Retired Ninja Sep 04 '13 at 13:33
  • @RetiredNinja: The example given shows both ends of the "pipe", so I doubt the packedness was really required. – ams Sep 04 '13 at 13:34
  • As long as they have acess to changing both sides. I thought `GetLoopOutMessage` might be a bit of a black box. – Retired Ninja Sep 04 '13 at 13:35
  • @RetiredNinja: yeah, it looks like the kind of black box that does a straight pass through of the data though. On second thoughts, the `sizeof` attribute suggests that it copies the data, so malloc/free may be a bad plan. – ams Sep 04 '13 at 13:38
  • Answer extended for that case. – ams Sep 04 '13 at 13:43
  • The compiler shows an error " invalid conversion of void* to SetAnalog at the *args=malloc.... – user2746930 Sep 04 '13 at 13:48
  • You're using C++? http://stackoverflow.com/questions/3477741/why-does-c-require-a-cast-for-malloc-but-c-doesnt – ams Sep 04 '13 at 13:53
  • You should probably use `new`/`delete` instead of malloc then. – ams Sep 04 '13 at 13:56
  • I don't do much C++, but I've converted the answer to what I think it should look like. – ams Sep 04 '13 at 14:05
  • You switched your answer. Did this not work for you, after all? – ams Sep 06 '13 at 08:57