473,388 Members | 1,400 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

variable number of parameters passed to sscanf() at runtime

Hi,

I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*. The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?

The only way to acheive this I can think of is to mess with the stack
using embedded asm and call the function myself, but i'm unsure how I
could make this reasonably safe and portable. What I really need is a
function defined like this:

int asscanf(const char* source, const char* fmt, void** storage, int
storage_size);

where storage is an array of void* pointers for storing the converted
data.

Has anybody come up against this problem before or suggest anyway to
tackle it?

-- Andrew

May 21 '06 #1
18 4774
Andrew wrote:
I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*.
An interpreter that contains printf-like (and scanf-like) functionality?
I can think of no other scenario that would require it, at this time.
The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?

The only way to acheive this I can think of is to mess with the stack
using embedded asm and call the function myself, but i'm unsure how I
could make this reasonably safe and portable. What I really need is a
function defined like this:

int asscanf(const char* source, const char* fmt, void** storage, int
storage_size);

where storage is an array of void* pointers for storing the converted
data.

Has anybody come up against this problem before or suggest anyway to
tackle it?

Yes, and the way to deal with it is to write your own "sscanf" using
string functions and istringstreams.

V
--
Please remove capital As from my address when replying by mail
May 21 '06 #2
The scenario is a simple but quite lengthy text protocol with messages
like so:

1 <formatted text>\n
2 <differently formatted text>\n
....

The first number is used to identify (amongst over things) the format
string used to extract further parameters from the rest of the string.
The idea being this will mute the need to do sscanf() (or other such
interpretation) calls in dozens of handler functions (there is atleast
1 for each message type).

May 21 '06 #3
"Andrew" <an******@gmail.com> wrote in message
news:11**********************@u72g2000cwu.googlegr oups.com...
Hi,

I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*. The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?

The only way to acheive this I can think of is to mess with the stack
using embedded asm and call the function myself, but i'm unsure how I
could make this reasonably safe and portable.


I'd say a asm block would be the shortest way to do this.
I made a very fast sample that compiles in vc++ 7 that
shows howto call a function inside a simple asm block.
You could with a asm block have a loop that pushes
the number of variables in your array onto the stack
and then calls sscanf, and afterwards pop the pushed
variables from the stack and continues.
You can do this with very little knowledge of assembly.

//eric

-- FILE stdafx.h --
#pragma once

#include <iostream>
#include <tchar.h>
-- EOF --
-- FILE asmtest.cpp --
#include "stdafx.h"
void testfunc(int i) {
std::cout << "void testfunc(int i): " << i << std::endl;
}
void testfunc2(int i, int j) {
std::cout << "void testfunc2(int i, int j): " << i << " " << j <<
std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
// calling with 1 arg
int i = 10, j = 20;
__asm {
PUSH i
CALL testfunc
POP i
}

// calling with 2 args
__asm {
PUSH j // arg 2 - read about calling convensions if you wonder why arg 2
is first ;)
PUSH i // arg 1
CALL testfunc2 // do the call
POP i // remove from stack
POP j // remove from stack
}
return 0;
}

-- EOF --
May 21 '06 #4
I've started an implementation of "asscanf", it doesn't yet work (it's
not even called). My assembler is rusty and i've never actually done
any inline assembler in C before. Here it is, it compiles in GCC 3.4.5
on Linux (I'm hoping to port to Win32 later but this is all for today).

I would appreciate anybody steering me in the right direction if i'm
going just plain wrong, and thank you for the replies so far.

-- Andrew
#include <iostream>
#include <stdio.h>

__attribute__((cdecl))
void testfunc2(int j, int i) {
std::cout << "void testfunc2(int i, int j): " << i << " " << j <<

std::endl;
}

int asscanf(const char *str, const char *format,
const int num_ptrs, const void** ptrs)
{
int i;
int result;

// Need to add moving of the stack pointers (increasing and
// shrinking the stack)

for(int i = num_ptrs; i > 0; i--)
{ asm("push %0;" :: "m" (ptrs[i])); }

asm(
"push %0;\n\t" // format
"push %1;\n\t" // str
"call sscanf;"
: "=a" (result)
: "m" (format), "m" (str)
);

for(int i = num_ptrs; i > 0; i--)
{ asm("pop;"); } // Discard everything I dumped on the stack

return result;
}

int main(int argc, char* argv[])
{
int i = 10, j = 20;

sscanf("54", "%i", &j);

// calling with 2 args
asm("push %0;\n\t" // push i
"push %1;\n\t" // push j
"call _Z9testfunc2ii;\n\t" // call 'testfunc2'
"pop %1;\n\t" // pop j }
"pop %0;\n\t" // pop i } cleanup
:
: "m" (i), "m" (j)
:
);

return 0;
}

May 21 '06 #5
"Andrew" <an******@gmail.com> skrev i en meddelelse
news:11**********************@i40g2000cwc.googlegr oups.com...
I've started an implementation of "asscanf", it doesn't yet work (it's
not even called). My assembler is rusty and i've never actually done
any inline assembler in C before. Here it is, it compiles in GCC 3.4.5
on Linux (I'm hoping to port to Win32 later but this is all for today). I would appreciate anybody steering me in the right direction if i'm
going just plain wrong, and thank you for the replies so far.


I never did any asm on linux or with gcc. However i just made the following
code for fun in vc++7 (win32). It uses printf to print out an int array.
Im posting it the hope that it can be any help to you.

//eric

/*
This code prints out the address in memory of each integer
in the array i[]. You can put as many integers into it as
you wish just remember to adjust the elements variable
*/
void PrintArrayAddrs(int *p, int s, int elements) {
/*
int *p - Pointer to last element in the array
int s - the size of a single element
int elements - the count of elements
*/
int c, h;
std::string strFormat;
strFormat = "Address of each variable in array:\n";
for (c=0, h=0; c<elements; c++, h++) {
strFormat += "%p ";
if (h == 7) {
strFormat += "\n";
h = 0;
}
}
const char *format = strFormat.c_str();
__asm {
mov eax,elements
mov ebx,p
PU_LOOP:
dec eax
push ebx
sub ebx,s
cmp eax,0
je _CALL
jmp PU_LOOP
_CALL:
push format
call printf
mov eax,elements
mov ebx,p
PO_LOOP:
dec eax
pop ebx
sub ebx,s
cmp eax,0
je DONE
jmp PO_LOOP
DONE:
pop format
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int i[10] = {10,20,30,40,50,60,70,80,90,100}; // array to print addresses
of with printf
// this array could be floats or whatever just change the types
int elements = 10;
PrintArrayAddrs(&i[elements-1], sizeof(int),elements);
system("pause");
return 0;
}
May 21 '06 #6
> for (c=0, h=0; c<elements; c++, h++) {
strFormat += "%p ";
if (h == 7) {
strFormat += "\n";
h = 0;
}
}


a little bug fix :)

if (h == 7) {
strFormat += "\n";
h = -1;
}
May 21 '06 #7
"Andrew" <an******@gmail.com> schrieb im Newsbeitrag news:11**********************@u72g2000cwu.googlegr oups.com...
Hi,

I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*. The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?

The only way to acheive this I can think of is to mess with the stack
using embedded asm and call the function myself, but i'm unsure how I
could make this reasonably safe and portable. What I really need is a
function defined like this:

int asscanf(const char* source, const char* fmt, void** storage, int
storage_size);

where storage is an array of void* pointers for storing the converted
data.

Has anybody come up against this problem before or suggest anyway to
tackle it?


Before you try something desparate, look for vsprintf.

HTH
Heinz
May 21 '06 #8
the vsprintf and vsscanf family use macro's to enable the compiler to
generate machine code for calling functions with a variable but known
number of arguments at _compile time_. The number of arguments for any
specific call must be known at _compile time_. This is not what I am
after.

Or am I wrong??

May 22 '06 #9
Andrew wrote:
Hi,

I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*. The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?


Probably the best answer: Not. The second answer would probably be, in
a loop,
passing one argument at a time. for-loops can use a dynamical upper
bound ;)

Of course, since this is C++, someone will point out that streams will
make
it even simpler.

HTH,
Michiel Salters

May 22 '06 #10
Andrew wrote:
Hi,

I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*. The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?
You don't, you use a stringstream:

# include <sstream>
# include <string>
# include <iostream>

int main()
{
std::string s = "just a 10 test";

std::string s1, s2, s3;
int i;

std::istringstream iss(s);
iss >> s1 >> s2 >> i >> s3;

std::cout << s1 << s2 << s3 << i;
}
The only way to acheive this I can think of is to mess with the stack
using embedded asm and call the function myself[...]
NooOOo!
int asscanf(const char* source, const char* fmt, void** storage, int
storage_size);

where storage is an array of void* pointers for storing the converted
data.


No no no no!

A combination of streams, containers, strings and perhaps boost::any
will solve your problem.
Jonathan

May 22 '06 #11
* Andrew:

I have a scenario in which both the source and format string for a
sscanf() call is selected *at runtime*. The number of format
conversions/substitutions is known as well as the maximum length of
each, so it's easy enough to allocate the memory required dynamically.

The problem is, how do I call sscanf()?

The only way to acheive this I can think of is to mess with the stack
using embedded asm and call the function myself, but i'm unsure how I
could make this reasonably safe and portable. What I really need is a
function defined like this:

int asscanf(const char* source, const char* fmt, void** storage, int
storage_size);

where storage is an array of void* pointers for storing the converted
data.

Has anybody come up against this problem before or suggest anyway to
tackle it?


I don't see that there's any problem.

You'll need to parse the format string anyway.

So just scan one item at a time.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 22 '06 #12
I found an excellent description of the va_list business here:

http://groups.google.com/group/comp....01f7ee1?hl=en&

Theoretically I could piece together a va_list structure at runtime and
pass it off that way, but after reading it's entirely not practical.

May 22 '06 #13
Thanks, that is an enlightening approach.

May 22 '06 #14
Andrew wrote:
Thanks, that is an enlightening approach.


Please learn to quote correctly on Usenet. See
http://en.wikipedia.org/wiki/Top-post#Inline_replies for more
informations and http://cfaj.freeshell.org/google/ if you are using
Google Groups.
Jonathan

May 22 '06 #15
You're right, I do need to tokenize the format string because the
formats are non-trivial. I'll reimplement a subset of the scanf
functionality using standard functions.

May 22 '06 #16
Eric Jensen wrote:
"Andrew" <an******@gmail.com> skrev i en meddelelse
news:11**********************@i40g2000cwc.googlegr oups.com...

-snip-
I would appreciate anybody steering me in the right direction if i'm
going just plain wrong, and thank you for the replies so far.

I never did any asm on linux or with gcc. However i just made the following
code for fun in vc++7 (win32). It uses printf to print out an int array.
Im posting it the hope that it can be any help to you.

//eric

/*
This code prints out the address in memory of each integer
in the array i[]. You can put as many integers into it as
you wish just remember to adjust the elements variable
*/
void PrintArrayAddrs(int *p, int s, int elements) {
/*
int *p - Pointer to last element in the array
int s - the size of a single element
int elements - the count of elements
*/
int c, h;
std::string strFormat;
strFormat = "Address of each variable in array:\n";
for (c=0, h=0; c<elements; c++, h++) {
strFormat += "%p ";
if (h == 7) {
strFormat += "\n";
h = 0;
}
}
const char *format = strFormat.c_str();
__asm {
mov eax,elements
mov ebx,p
PU_LOOP:
dec eax
push ebx
sub ebx,s
cmp eax,0
je _CALL
jmp PU_LOOP
_CALL:
push format
call printf
mov eax,elements
mov ebx,p
PO_LOOP:
dec eax
pop ebx
sub ebx,s
cmp eax,0
je DONE
jmp PO_LOOP
DONE:
pop format
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int i[10] = {10,20,30,40,50,60,70,80,90,100}; // array to print addresses
of with printf
// this array could be floats or whatever just change the types
int elements = 10;
PrintArrayAddrs(&i[elements-1], sizeof(int),elements);
system("pause");
return 0;
}


How to make that work on g++?

g++ -fasm-blocks asm.c
asm.c: In function 'void PrintArrayAddrs(int*, int, int)':
asm.c:13: error: 'string' is not a member of 'std'
asm.c:13: error: expected `;' before 'strFormat'
asm.c:14: error: 'strFormat' was not declared in this scope
asm.c: At global scope:
asm.c:49: error: '_TCHAR' has not been declared
asm.c: In function 'int _tmain(int, int**)':
asm.c:52: error: 'of' was not declared in this scope
asm.c:52: error: expected `;' before 'with'
asm.c:55: error: 'elements' was not declared in this scope
Best regards / Med venlig hilsen
Martin Jørgensen

--
---------------------------------------------------------------------------
Home of Martin Jørgensen - http://www.martinjoergensen.dk
May 22 '06 #17
Martin Jørgensen wrote:
Eric Jensen wrote:
"Andrew" <an******@gmail.com> skrev i en meddelelse
news:11**********************@i40g2000cwc.googlegr oups.com...

-snip-
I would appreciate anybody steering me in the right direction if i'm
going just plain wrong, and thank you for the replies so far.

I never did any asm on linux or with gcc. However i just made the
following code for fun in vc++7 (win32). It uses printf to print out
an int array. Im posting it the hope that it can be any help to you.

//eric

/*
This code prints out the address in memory of each integer
in the array i[]. You can put as many integers into it as
you wish just remember to adjust the elements variable
*/
void PrintArrayAddrs(int *p, int s, int elements) {
[..]
__asm {
[..]
}
}
[..]


How to make that work on g++?

[..]


Built-in assembly is (a) platform-specific, (b) is defined to begin with
'asm' keyword, not '__asm' and (c) implementation-defined. If you need
a platform-specific compiler-specific solution, please consider taking
this conversation to a more appropriate newsgroup. Let's keep this about
C++ and not about Linux, Windows, GCC, VC++, etc.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
May 23 '06 #18
Martin Jørgensen wrote:
Eric Jensen wrote:
"Andrew" <an******@gmail.com> skrev i en meddelelse
news:11**********************@i40g2000cwc.googlegr oups.com... -snip-
I would appreciate anybody steering me in the right direction if i'm
going just plain wrong, and thank you for the replies so far.

I never did any asm on linux or with gcc. However i just made the following
code for fun in vc++7 (win32). It uses printf to print out an int array.
Im posting it the hope that it can be any help to you.

//eric

/*
This code prints out the address in memory of each integer
in the array i[]. You can put as many integers into it as
you wish just remember to adjust the elements variable
*/
void PrintArrayAddrs(int *p, int s, int elements) {
/*
int *p - Pointer to last element in the array
int s - the size of a single element
int elements - the count of elements
*/
int c, h;
std::string strFormat;
strFormat = "Address of each variable in array:\n";
for (c=0, h=0; c<elements; c++, h++) {
strFormat += "%p ";
if (h == 7) {
strFormat += "\n";
h = 0;
}
}
const char *format = strFormat.c_str();
__asm {
mov eax,elements
mov ebx,p
PU_LOOP:
dec eax
push ebx
sub ebx,s
cmp eax,0
je _CALL
jmp PU_LOOP
_CALL:
push format
call printf
mov eax,elements
mov ebx,p
PO_LOOP:
dec eax
pop ebx
sub ebx,s
cmp eax,0
je DONE
jmp PO_LOOP
DONE:
pop format
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int i[10] = {10,20,30,40,50,60,70,80,90,100}; // array to print addresses
of with printf
// this array could be floats or whatever just change the types
int elements = 10;
PrintArrayAddrs(&i[elements-1], sizeof(int),elements);
system("pause");
return 0;
}


How to make that work on g++?


How about searching a bit before asking?
g++ -fasm-blocks asm.c
asm.c: In function 'void PrintArrayAddrs(int*, int, int)':
asm.c:13: error: 'string' is not a member of 'std'
asm.c:13: error: expected `;' before 'strFormat'
asm.c:14: error: 'strFormat' was not declared in this scope
# include <string>
asm.c: At global scope:
asm.c:49: error: '_TCHAR' has not been declared
_TCHAR doesn't exist in standard C++. Make it a const char*.
asm.c: In function 'int _tmain(int, int**)':
int main()
asm.c:52: error: 'of' was not declared in this scope
asm.c:52: error: expected `;' before 'with'
Seriously?? The comment is on two lines! Wake up!
asm.c:55: error: 'elements' was not declared in this scope


Probably because of the other errors.
Jonathan

May 23 '06 #19

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Edward | last post by:
ASP.NET / VB.NET SQL Server 7.0 Our client has insisted that we change our established practice of building SQL in-line and move it all to SPROCs. Not a problem for 80% of the app. However,...
7
by: Kapt. Boogschutter | last post by:
I'm trying to create a function that has at least 1 Argument but can also contain any number of Arguments (except 0 because my function would have no meaning for 0 argument). The arguments...
7
by: Edward Yang | last post by:
A few days ago I started a thread "I think C# is forcing us to write more (redundant) code" and got many replies (more than what I had expected). But after reading all the replies I think my...
10
by: Blaxer | last post by:
There is probably a really easy way to do this, so please forgive me but I would like to set the value of a variable from a variable, an example would be... function Calculate_Something(ByVal...
6
by: John | last post by:
I'm new to C and I know this is probably one of those "most commonly mis-interpreted as a problem", newcomer type of question, but for this code: double x; printf("Enter number:");...
18
by: John Friedland | last post by:
My problem: I need to call (from C code) an arbitrary C library function, but I don't know until runtime what the function name is, how many parameters are required, and what the parameters are. I...
3
by: Skip | last post by:
OK, I'm a novice in JS but have lots of coding experience. I am trying to accomplish something that would seem somewhat simple - BUT IT'S NOT. I have a basic window that calls another window...
11
by: Googy | last post by:
Hi friends!! As we know that the input parameters in a function is fixed when the function is defined but how does printf processes variable number of input arguments ? For example: 1....
5
by: imailz | last post by:
Hi all, since I'm forced to switch from Fortran to C I wonder if there is posibility in C: 1) to use implicit loops 2) to parse several variables which number is determined at runtime. ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.