473,739 Members | 11,435 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Passing function pointer as argument to a function???

The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.

Can someone help me understand exactly what I'm passing to
the qsort function in the "bad" code other than the pointer
to a function and/or how this differs from the "good" code?

How could the qsort statement be written directly without
the use of an intermediary like 'fcmp' ?

Thanks for your help.

Regards,
Charles Sullivan



Nov 15 '05 #1
17 3597


Charles Sullivan wrote On 09/19/05 11:05,:
The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
FYI: The `&' is harmless but unnecessary, both here
and below.
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.

Can someone help me understand exactly what I'm passing to
the qsort function in the "bad" code other than the pointer
to a function and/or how this differs from the "good" code?
Well, let's see: The compiler says that cmp_fcn() is
of the wrong type. Might this mean that there's something
wrong with cmp_fcn()? It seems a possibility, doesn't it?
However, this is all just speculation on my part, since you
haven't (hint, hint) shown what cmp_fcn() looks like ...
How could the qsort statement be written directly without
the use of an intermediary like 'fcmp' ?


By writing a cmp_fcn() that matches what qsort()
requires.

--
Er*********@sun .com

Nov 15 '05 #2
Charles Sullivan wrote:

The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.
qsort is expecting a pointer to a function which returns an int and
gets passed two const void * parameters. However, you are passing
it a pointer to a function which returns int and gets passed a
variable number of unknown parameters.
Can someone help me understand exactly what I'm passing to
the qsort function in the "bad" code other than the pointer
to a function and/or how this differs from the "good" code?
When using the intermediate fcmp variable, you are passing it
a function which returns int, and whose parameters are left
unprototyped.
How could the qsort statement be written directly without
the use of an intermediary like 'fcmp' ?


If cmp_fcn() does, in fact, take two const void * parameters, then
say so by changing:

int cmp_fcn(...);
to
int cmp_fcn(const void *,const void *);

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer .h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th***** ********@gmail. com>

Nov 15 '05 #3
Charles Sullivan wrote:
The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.

Can someone help me understand exactly what I'm passing to
the qsort function in the "bad" code other than the pointer
to a function and/or how this differs from the "good" code?

How could the qsort statement be written directly without
the use of an intermediary like 'fcmp' ?


Exactly as you use fcmp. To clarify:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#define ASIZE 10

int cmp_fcn(const void *e1, const void *e2);

int main(void)
{
double asrc[ASIZE], awrk[ASIZE];
int (*fcmp) () = cmp_fcn;
size_t i;
srand(time(0));
printf(" example using cmp_fcn as argument\n");
for (i = 0; i < ASIZE; i++)
asrc[i] = rand() / (1. + RAND_MAX);
memcpy(awrk, asrc, sizeof asrc);
qsort(awrk, ASIZE, sizeof *awrk, cmp_fcn);
for (i = 0; i < ASIZE; i++)
printf("%lu: %f %f\n", (unsigned long) i, asrc[i], awrk[i]);
printf("\n");

printf(" example using fcmp as argument\n");
for (i = 0; i < ASIZE; i++)
asrc[i] = rand() / (1. + RAND_MAX);
memcpy(awrk, asrc, sizeof asrc);
qsort(awrk, ASIZE, sizeof *awrk, fcmp);
for (i = 0; i < ASIZE; i++)
printf("%lu: %f %f\n", (unsigned long) i, asrc[i], awrk[i]);
return 0;
}
int cmp_fcn(const void *e1, const void *e2)
{
const double *p1 = e1, *p2 = e2;
return (*p1 > *p2) ? 1 : (*p1 < *p2) ? -1 : 0;
}

example using cmp_fcn as argument
0: 0.563498 0.111813
1: 0.195851 0.195851
2: 0.111813 0.254336
3: 0.294201 0.294201
4: 0.318893 0.318893
5: 0.586812 0.511567
6: 0.724280 0.563498
7: 0.925669 0.586812
8: 0.511567 0.724280
9: 0.254336 0.925669

example using fcmp as argument
0: 0.887919 0.053615
1: 0.053615 0.134536
2: 0.471209 0.211441
3: 0.457827 0.240006
4: 0.640444 0.457827
5: 0.211441 0.471209
6: 0.240006 0.511690
7: 0.511690 0.640444
8: 0.699548 0.699548
9: 0.134536 0.887919
Nov 15 '05 #4
Kenneth Brody <ke******@spamc op.net> writes:
Charles Sullivan wrote:

The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.


qsort is expecting a pointer to a function which returns an int and
gets passed two const void * parameters. However, you are passing
it a pointer to a function which returns int and gets passed a
variable number of unknown parameters.


No, he's not. A function that takes a variable number of arguments
must have at least one named argument before the "...". Note also his
use of "..." in the call to qsort. The ellipsis isn't being used as C
syntax; it's just an ellipsis.

He's just not showing us exactly what he's doing -- which means we
can't guess what the problem is.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #5
Charles Sullivan wrote on 19/09/05 :
The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
You don't need the &.
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);
You don't need the &.

qsort(..., cmp_fcn);
the compiler complains about incompatible pointer type.
How exactly is cmp_fcn() prototyped ?
Can someone help me understand exactly what I'm passing to
the qsort function in the "bad" code other than the pointer
to a function and/or how this differs from the "good" code?
The compare function must exactly have this prototype :

int compare_functio n (void const *, void const *);
How could the qsort statement be written directly without
the use of an intermediary like 'fcmp' ?


Using the correct prototype for the compare function. We all do that
every day... (well, sort of)

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

I once asked an expert COBOL programmer, how to
declare local variables in COBOL, the reply was:
"what is a local variable?"
Nov 15 '05 #6
On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
Kenneth Brody <ke******@spamc op.net> writes:
Charles Sullivan wrote:

The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.


qsort is expecting a pointer to a function which returns an int and
gets passed two const void * parameters. However, you are passing
it a pointer to a function which returns int and gets passed a
variable number of unknown parameters.


No, he's not. A function that takes a variable number of arguments
must have at least one named argument before the "...". Note also his
use of "..." in the call to qsort. The ellipsis isn't being used as C
syntax; it's just an ellipsis.

He's just not showing us exactly what he's doing -- which means we
can't guess what the problem is.


Mea culpa. I had forgotten about the C syntax and used "..." to
represent stuff I _thought_ irrelevant to the question.

Here's an example which illustrates the way I've been using
qsort:
-------------------------------------
#include <stdio.h>
#include <stdlib.h>

int val[] = { 3, 2, 1, 4, 5 };

int cmp_fcn ( int *one, int *two )
{
return (*one < *two) ? -1 :
(*one > *two) ? 1 : 0;
}

int main ( void )
{
int (*fcmp)() = &cmp_fcn;
qsort((void *)val, 5, sizeof(int), fcmp);
printf("%d %d %d %d %d\n",
val[0], val[1], val[2], val[3], val[4]);
return 0;
}
-----------------------------------

Regards,
Charles Sullivan

Nov 15 '05 #7
On Mon, 19 Sep 2005 23:36:43 GMT, Charles Sullivan
<cw******@triad .rr.com> wrote:
On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
Kenneth Brody <ke******@spamc op.net> writes:
Charles Sullivan wrote:

The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.

qsort is expecting a pointer to a function which returns an int and
gets passed two const void * parameters. However, you are passing
it a pointer to a function which returns int and gets passed a
variable number of unknown parameters.
No, he's not. A function that takes a variable number of arguments
must have at least one named argument before the "...". Note also his
use of "..." in the call to qsort. The ellipsis isn't being used as C
syntax; it's just an ellipsis.

He's just not showing us exactly what he's doing -- which means we
can't guess what the problem is.


Mea culpa. I had forgotten about the C syntax and used "..." to
represent stuff I _thought_ irrelevant to the question.

Here's an example which illustrates the way I've been using
qsort:
-------------------------------------
#include <stdio.h>
#include <stdlib.h>

int val[] = { 3, 2, 1, 4, 5 };

int cmp_fcn ( int *one, int *two )


cmp_fcn has the wrong type for a function whose address is to be
passed to qsort. The two parameters need to be const void *.
{
return (*one < *two) ? -1 :
(*one > *two) ? 1 : 0;
}

int main ( void )
{
int (*fcmp)() = &cmp_fcn;
fcmp has the wrong type for a pointer to be used as an argument to
qsort. fcmp is a pointer to function (returning int) about whose
arguments (type and quantity) absolutely nothing is known. qsort
needs a pointer to function returning int about whose arguments
everything is known.
qsort((void *)val, 5, sizeof(int), fcmp);
printf("%d %d %d %d %d\n",
val[0], val[1], val[2], val[3], val[4]);
return 0;
}


Try increasing the warning level on your compiler.
<<Remove the del for email>>
Nov 15 '05 #8
Charles Sullivan <cw******@triad .rr.com> writes:
On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
Kenneth Brody <ke******@spamc op.net> writes:
Charles Sullivan wrote:
The library function 'qsort' is declared thus:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(co nst void *, const void *));

If in my code I write:
int cmp_fcn(...);
int (*fcmp)() = &cmp_fcn;
qsort(..., fcmp);

then everything works. But if instead I code qsort as:

qsort(..., &cmp_fcn);

the compiler complains about incompatible pointer type.

qsort is expecting a pointer to a function which returns an int and
gets passed two const void * parameters. However, you are passing
it a pointer to a function which returns int and gets passed a
variable number of unknown parameters.


No, he's not. A function that takes a variable number of arguments
must have at least one named argument before the "...". Note also his
use of "..." in the call to qsort. The ellipsis isn't being used as C
syntax; it's just an ellipsis.

He's just not showing us exactly what he's doing -- which means we
can't guess what the problem is.


Mea culpa. I had forgotten about the C syntax and used "..." to
represent stuff I _thought_ irrelevant to the question.

Here's an example which illustrates the way I've been using
qsort:
-------------------------------------
#include <stdio.h>
#include <stdlib.h>

int val[] = { 3, 2, 1, 4, 5 };

int cmp_fcn ( int *one, int *two )
{
return (*one < *two) ? -1 :
(*one > *two) ? 1 : 0;
}

int main ( void )
{
int (*fcmp)() = &cmp_fcn;
qsort((void *)val, 5, sizeof(int), fcmp);
printf("%d %d %d %d %d\n",
val[0], val[1], val[2], val[3], val[4]);
return 0;
}
-----------------------------------


Yup, the stuff you deleted was exactly what's relevant to the problem.

The "compar" argument to qsort must be a pointer to a function taking
two arguments of type "const void *" and returning a result of type
int. You're providing a pointer to a function taking two arguments of
type int* and returning a result of type int. The types are
incompatible.

You need to declare your cmp_fcn() function as:

int cmp_fcn(const void *one, const void *2);

Here's a modified version of your program:

#include <stdio.h>
#include <stdlib.h>

int val[] = { 3, 2, 1, 4, 5 };

int cmp_fcn ( const void *one, const void *two )
{
return (*(int*)one < *(int*)two) ? -1 :
(*(int*)one > *(int*)two) ? 1 : 0;
}

int main ( void )
{
qsort(val,
sizeof val / sizeof val[0],
sizeof val[0],
cmp_fcn);
printf("%d %d %d %d %d\n",
val[0], val[1], val[2], val[3], val[4]);
return 0;
}

Note that I've changed all four arguments to qsort().

For the first argument, I dropped the cast to void*. As long as
qsort's prototype is visible (which it is, since you have the
"#include <stdlib.h>", the conversion is done implicitly.

For the second argument, I compute the size of the val array rather
than assuming it's 5. This lets you change the size without having
to modify the call.

Similarly, the third argument is "sizeof val[0]" rather than
"sizeof(int )", allowing you to change the type of the array without
changing the qsort call (though you would have to change the
cmp_fcn function).

Finally, I pass the name of the function directly to qsort() rather
than storing it in a variable. The name of a function is implicitly
converted to a pointer-to-function in most contexts. (The exceptions
are the argument to sizeof, which makes "sizeof func" illegal rather
than yielding the size of a function pointer, and the argument to a
unary "&" operator, which makes &func nearly equivalent to func.)

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #9
On Mon, 19 Sep 2005 17:44:30 -0700, Barry Schwarz wrote:
On Mon, 19 Sep 2005 23:36:43 GMT, Charles Sullivan
<cw******@triad .rr.com> wrote:
On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
Kenneth Brody <ke******@spamc op.net> writes:
Charles Sullivan wrote:
>
> The library function 'qsort' is declared thus:
> void qsort(void *base, size_t nmemb, size_t size,
> int(*compar)(co nst void *, const void *));
>
> If in my code I write:
> int cmp_fcn(...);
> int (*fcmp)() = &cmp_fcn;
> qsort(..., fcmp);
>
> then everything works. But if instead I code qsort as:
>
> qsort(..., &cmp_fcn);
>
> the compiler complains about incompatible pointer type.

qsort is expecting a pointer to a function which returns an int and
gets passed two const void * parameters. However, you are passing
it a pointer to a function which returns int and gets passed a
variable number of unknown parameters.

No, he's not. A function that takes a variable number of arguments
must have at least one named argument before the "...". Note also his
use of "..." in the call to qsort. The ellipsis isn't being used as C
syntax; it's just an ellipsis.

He's just not showing us exactly what he's doing -- which means we
can't guess what the problem is.


Mea culpa. I had forgotten about the C syntax and used "..." to
represent stuff I _thought_ irrelevant to the question.

Here's an example which illustrates the way I've been using
qsort:
-------------------------------------
#include <stdio.h>
#include <stdlib.h>

int val[] = { 3, 2, 1, 4, 5 };

int cmp_fcn ( int *one, int *two )


cmp_fcn has the wrong type for a function whose address is to be
passed to qsort. The two parameters need to be const void *.
{
return (*one < *two) ? -1 :
(*one > *two) ? 1 : 0;
}

int main ( void )
{
int (*fcmp)() = &cmp_fcn;


fcmp has the wrong type for a pointer to be used as an argument to
qsort. fcmp is a pointer to function (returning int) about whose
arguments (type and quantity) absolutely nothing is known. qsort
needs a pointer to function returning int about whose arguments
everything is known.
qsort((void *)val, 5, sizeof(int), fcmp);
printf("%d %d %d %d %d\n",
val[0], val[1], val[2], val[3], val[4]);
return 0;
}


Try increasing the warning level on your compiler.


OK, if I change the function as suggested by you all to:
--------------------
int cmp_fcn ( const void *x1, const void *x2 )
{
const int *one = x1; const int *two = x2;
return (*one < *two) ? -1 :
(*one > *two) ? 1 : 0;
}
--------------------
then it works both ways. (Thanks guys.)

But I've yet to find a (gcc-3.2.2-5) compiler warning level that
grunts even a little with my original (working) code. As far as
I can remember I've used that syntax on a variety of Unix-like
systems over the years and never got a warning about it.

Thanks for all your help.

Regards,
Charles Sullivan
Nov 15 '05 #10

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

Similar topics

58
10167
by: jr | last post by:
Sorry for this very dumb question, but I've clearly got a long way to go! Can someone please help me pass an array into a function. Here's a starting point. void TheMainFunc() { // Body of code... TCHAR myArray; DoStuff(myArray);
4
4255
by: Vijai Kalyan | last post by:
I was decomposing a task into different policies. Essentially, there is a general option obtained from a server and user options obtained from configuration variables. The two options are complementary to one another. So I proceeded to decompose the tasks that deal with user options into two functions. Each of the functions do something and towards the end they do supplementary tasks that depend on the server option. The whole things...
3
2879
by: Goh, Yong Kwang | last post by:
I'm trying to create a function that given a string, tokenize it and put into a dynamically-sized array of char* which is in turn also dynamically allocated based on the string token length. I call the function using this code fragement in my main function: --- char** arg_array; arg_count = create_arg_array(command, argument, arg_array); for(count = 0; count < arg_count; count++)
6
8259
by: bob_jenkins | last post by:
{ const void *p; (void)memset((void *)p, ' ', (size_t)10); } Should this call to memset() be legal? Memset is of type void *memset(void *, unsigned char, size_t) Also, (void *) is the generic pointer type. My real question is, is (void *) such a generic pointer type that it
9
5294
by: Juggernaut | last post by:
I am trying to create a p_thread pthread_create(&threads, &attr, Teste, (void *)var); where var is a char variable. But this doesnt't work, I get this message: test.c:58: warning: cast to pointer from integer of different size. Now I thought that when it was a void I could pass anything? Thing is it works when I use an int, but in this case I wanted to use a char. It wouldnt be hard to work around it, but it annoys me because I've heard...
11
4465
by: truckaxle | last post by:
I am trying to pass a slice from a larger 2-dimensional array to a function that will work on a smaller region of the array space. The code below is a distillation of what I am trying to accomplish. // - - - - - - - - begin code - - - - - - - typedef int sm_t; typedef int bg_t; sm_t sm; bg_t bg;
7
3019
by: Jeff K | last post by:
Can you pass an int array by reference to a function and modify selective elements? Here is my code: #include <stdio.h> #define COLUMNSIZE 30 #define ASIZE 5 int calcfldpos(int *row, int *column, int *numArray)
7
2635
by: Jake Thompson | last post by:
Hello I created a DLL that has a function that is called from my main c program. In my exe I first get a a pointer to the address of the function by using GetProcAddress and on the dll side I make sure that my function is being exported by adding a line to the .def file. This seems to work because when I debug it recognizes the dll and once it hits the function it goes right into the proper location of the dll.
3
2381
by: sd2004 | last post by:
I am still learning, could someone show/explain to me how to fix the error. I can see it is being wrong but do not know how to fix. could you also recommend a book that I can ref. to ? ////////////////// ERROR MESSAGE ///////////////////// bash-2.05b$ g++ test5c.cpp test5c.cpp: In function `int main()': test5c.cpp:36: error: invalid initialization of reference of type
0
8792
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9337
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9266
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9209
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8215
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6054
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4826
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2748
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2193
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.