Skip to main content
GameDev.net gamedev.net
🔒 Locked

sprintf and sprintf_s

Started by donguow Feb 10, 2012 at 4:41 AM 26 replies 8.4k views
Original Post
donguow
donguow
Hi guys,

I'm trying to send a sequence of floats over the network and here are several steps that I am following:

  1. Convert a float to a string (or char*)
  2. send the string to the client (using socket
  3. Repeat (1), (2) till the last float

I'm stuck at step (1): converting an float to a string. I'm using sprintf to do that (I've also tried with sprintf_s) but it doesn't work.


float bufferData[] = {
5.81414, 5.49492, 3.87633,
6.58321, 4.59523, 4.4363,
6.54791, 4.60198, 4.43473,
5.81414, 5.49492, 3.87633,
//.........
//.........
6.54791, 4.60198, 4.43473,
6.01867, 4.9006, 4.2733,
5.81414, 5.49492, 3.87633,
};

int N = sizeof(bufferData)/sizeof(float);

for (int i = 0; i < N; i++)
{
sprintf(buf, "%f", bufferData);
//send buf to the client
}


Error msg:
[bquote]
Unhandled exception at 0x00412fd0 in hybrid-rendering.exe: 0xC0000005: Access violation reading location 0x00000000.
[/bquote]

I know that it's pretty unsafe when using sprintf as we don't know the size of data in advance. So is there any alternative ways to do that sort of things? if someone knows how to fix this, please share with me, I will really appreaciate your help.

Thanks,
Dong
Hodgman
Hodgman
Where do you define [font=courier new,courier,monospace]buf[/font]? Is it a null pointer?
donguow
donguow
sorry, I forgot to mention it.
Here it is:
char buf[20];
donguow
donguow
There is another error msg:

bufferData 0x00000000 float *

CXX0030: Error: expression cannot be evaluated
donguow
donguow
My temporary solution now is using itoa (convert an integer to a string) instead of sprintf.

Server:

int temp;
float a;

for (int i = 0; i < N; i++)
{
a = bufferData * 1000000;
temp = (int)a;
itoa(temp, buf, 10);
// ...
send(sClient, buf, BUF_SIZE, 0);
}


Client:

int temp = 0;
float a;

for (int i = 0; i < N; i++)
{
recv(sServer, buf, BUF_SIZE, 0);
temp = atoi(buf);
a = (float) temp / 1000000;
//...
}
CodeCriminal
CodeCriminal

This is working for me.. after adding char buf[16]; above the for loop.. are you sure the problem is within that snippet of code you posted?

EDIT: Oh but MSVC did scream at me for truncating doubles to floats (i.e. you need to append the suffix f to all those values in bufferData. C can get a little funny sometimes with data types and formating functions..

donguow
donguow
It works for me sometimes as well but not in this case. I aim to get data from a buffer and send it to a different machine.
Here are how I did:

  1. First, I try to get the data out of the buffer by doing: glBindBuffer(GL_ARRAY_BUFFER, vboid);
    float* bufferData = (float*) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);

  2. Then, I send this data to the client as I did above
  3. And finally, unmap the buffer glUnmapBuffer(GL_ARRAY_BUFFER);

Do you have any idea, Roadysix?
CodeCriminal
CodeCriminal
Judging by your error message above, glMapBuffer is returning NULL, id suggest checking what the error message of glMapBuffer is first.
rip-off
rip-off
You almost certainly shouldn't be reading data from OpenGL and writing it to the network. Give us a high level view of what you are doing, there is probably an easier way.
donguow
donguow

You almost certainly shouldn't be reading data from OpenGL and writing it to the network.

I just want to test something regardless of whether it is a good idea or not so just give it a try

Give us a high level view of what you are doing, there is probably an easier way.

My purpose is to get the data out of the buffer (say a vertex buffer) and then transmitt it to another machine to be further processed.
donguow
donguow

Judging by your error message above, glMapBuffer is returning NULL

Thanks Roadysix, but I don't really get this, what do you mean by glMapBuffer is returning NULL. Anw, proabably the errors are due to glMapBuffer/glUnmapBuffer, I will check this out
Hodgman
Hodgman
Unhandled exception at 0x00412fd0 in hybrid-rendering.exe: 0xC0000005: Access violation reading location 0x00000000.
Backing up for a minute, you just need to use your debugger a bit here ---
Firstly, when you get an error like this, an important thing to take note of is the line that the debugger has halted on. Secondly, if you're running in debug mode, you can then use the 'watch' window (or hover your cursor over a variable name, or other equivalent depending on your IDE/debugger) to inspect the values of your variables.

NULL is simply another name for "0", so if you get the error "Access violation reading location 0" that means your program has told the computer to try to read data from a NULL pointer, which causes a crash. When you crash and look at the value of bufferData, I'm guessing it will be 0/NULL.

Also, it's good practice to self-document any dangerous assumptions in your code via assertions. For example, in this case, you're assuming that bufferData is not NULL, so I would write:float* bufferData = (float*) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
assert( bufferData != NULL );
Then, your code will still crash, but it will crash with an assertion failure, which immediately tells you which assumption is incorrect.
rip-off
rip-off

My purpose is to get the data out of the buffer (say a vertex buffer) and then transmitt it to another machine to be further processed.
[/quote]
That isn't a high level view of what you are trying. That is a low level description of the steps you are following, and isn't even at a higher level than the code you were showing.

Knowing the high level goal can help because we can offer alternative solutions which you might not have considered.


I just want to test something regardless of whether it is a good idea or not
[/quote]
Fair enough.
donguow
donguow

[quote name='donguow' timestamp='1328848911' post='4911543']Unhandled exception at 0x00412fd0 in hybrid-rendering.exe: 0xC0000005: Access violation reading location 0x00000000.
Backing up for a minute, you just need to use your debugger a bit here ---
Firstly, when you get an error like this, an important thing to take note of is the line that the debugger has halted on. Secondly, if you're running in debug mode, you can then use the 'watch' window (or hover your cursor over a variable name, or other equivalent depending on your IDE/debugger) to inspect the values of your variables.

NULL is simply another name for "0", so if you get the error "Access violation reading location 0" that means your program has told the computer to try to read data from a NULL pointer, which causes a crash. When you crash and look at the value of bufferData, I'm guessing it will be 0/NULL.

Also, it's good practice to self-document any dangerous assumptions in your code via assertions. For example, in this case, you're assuming that bufferData is not NULL, so I would write:float* bufferData = (float*) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
assert( bufferData != NULL );
Then, your code will still crash, but it will crash with an assertion failure, which immediately tells you which assumption is incorrect.
[/quote]
This is very useful to me. Thank Hodgman
donguow
donguow

That isn't a high level view of what you are trying. That is a low level description of the steps you are following, and isn't even at a higher level than the code you were

I want to break up the rendering pipeline in a sense that the computational workload can be shared between the server and the client. In other words, I want the server to perform some tasks of the rendering (like calculating vertex positions, color) and the client will be responsible for the remaining tasks. I know that by using Transform feedback we can be able to achieve something in the middle, like the server can calculate vertex positions and then store the result into a buffer. What I have presented ealier is trying to send this data to the client for futher processing.
Hope my description make sense to you?
gdboy
gdboy
[color=#000088]float[color=#000000] bufferData[color=#666600][][color=#000000] [color=#666600]=[color=#000000] [color=#666600]{
[color=#006666]5.81414[color=#666600],[color=#000000] [color=#006666]5.49492[color=#666600],[color=#000000] [color=#006666]3.87633[color=#666600],
[color=#006666]6.58321[color=#666600],[color=#000000] [color=#006666]4.59523[color=#666600],[color=#000000] [color=#006666]4.4363[color=#666600],
[color=#006666]6.54791[color=#666600],[color=#000000] [color=#006666]4.60198[color=#666600],[color=#000000] [color=#006666]4.43473[color=#666600],
[color=#006666]5.81414[color=#666600],[color=#000000] [color=#006666]5.49492[color=#666600],[color=#000000] [color=#006666]3.87633[color=#666600],
[color=#880000]//.........
[color=#880000]//.........
[color=#006666]6.54791[color=#666600],[color=#000000] [color=#006666]4.60198[color=#666600],[color=#000000] [color=#006666]4.43473[color=#666600],
[color=#006666]6.01867[color=#666600],[color=#000000] [color=#006666]4.9006[color=#666600],[color=#000000] [color=#006666]4.2733[color=#666600],
[color=#006666]5.81414[color=#666600],[color=#000000] [color=#006666]5.49492[color=#666600],[color=#000000] [color=#006666]3.87633[color=#666600],
[color=#666600]};

[color=#000088]int[color=#000000] N [color=#666600]=[color=#000000] [color=#000088]sizeof[color=#666600]([color=#000000]bufferData[color=#666600])/[color=#000088]sizeof[color=#666600]([color=#000088]float[color=#666600]);
int offset=0;
char buf[2000];//big enough
[color=#000088]for[color=#000000] [color=#666600]([color=#000088]int[color=#000000] i [color=#666600]=[color=#000000] [color=#006666]0[color=#666600];[color=#000000] i [color=#666600]<[color=#000000] N[color=#666600];[color=#000000] i[color=#666600]++)
[color=#666600]{
[color=#000000] sprintf[color=#666600]([color=#000000]buf+offset[color=#666600],[color=#000000] [color=#008800]"%f "[color=#666600],[color=#000000] bufferData[color=#666600][[color=#000000]i[color=#666600]]);//Leave a blank space behind %f, since you want to [color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

decode it later.

[/font]
[color=#666600] offset+=strlen(buf+offset);
[color=#000000] [color=#880000]//send buf to the client
[color=#666600]}

21st Century Moose
21st Century Moose
Any specific reason to not send the floats as binary? You'll get better performance in the transmission owing to not have to encode/decode, and have considerably less complex code.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
Antheus
Antheus

I want to break up the rendering pipeline in a sense that the computational workload can be shared between the server and the client. In other words, I want the server to perform some tasks of the rendering (like calculating vertex positions, color) and the client will be responsible for the remaining tasks.


Only problem is that network will be a bottleneck, even at best it's up to million times slower than PCIe. PCIe is a bottleneck even with local readbacks and is not a viable solution for CUDA-like algorithms or rendering.

For example, processing a 1080p-sized float texture can be done 100,000 times per second, but even the fastest gigabit networks will only be able to transmit <10 such frames per second.
iMalc
iMalc

Any specific reason to not send the floats as binary? You'll get better performance in the transmission owing to not have to encode/decode, and have considerably less complex code.
At the very least this means that you don't destroy values such as infs, nans, denormals, large numbers, and values that are otherwise not exactly representable using the very rough temporary scheme that you have now.

Alternatively, I would convert the raw binary of the floats into hex in order to transmit them as text and convert the hex back into raw binary at the other end. Base64 is another option when you have to transmit as text.
Six222
Six222
If your using C++ you could(and should) use streams...


float bufferData[] = {
5.81414, 5.49492, 3.87633,
6.58321, 4.59523, 4.4363,
6.54791, 4.60198, 4.43473,
5.81414, 5.49492, 3.87633,
//.........
//.........
6.54791, 4.60198, 4.43473,
6.01867, 4.9006, 4.2733,
5.81414, 5.49492, 3.87633,
};

std::string buf;
int N = sizeof(bufferData)/sizeof(float);

for (int i = 0; i < N; i++)
{
buf << bufferData[N] << std::endl;
}


And then you can just convert that string to a char* using buf.c_str(). This method is iirc faster and you don't have to worry about initilizing.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.