473,386 Members | 1,673 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,386 software developers and data experts.

Calling C++ class method from C

24
Hello guys,

Ok here is the issue/roadblock. I am trying to call a method that is a member of a c++ class. I know I need to have a wrapper function to give C a pointer to the member function. I have created a shared header file <header.h> and 2 source files. <cSource.c> and <cppSource.cpp>. Then of course the main file written in c. <cMain.c>

If anyone could help me get this small example working so that I can experiment with the actual problem I'm trying to overcome it would be absolutely terrific.

Here is the code I have:
(the commands to compile and errors located at the end of post)

header.h
Expand|Select|Wrap|Line Numbers
  1. /*Start CPP header information */
  2. #ifndef HEADER_H
  3. #define HEADER_H
  4.  
  5.     #ifdef __cplusplus
  6.         class cClass
  7.         {
  8.             public:
  9.  
  10.                 void sayHello();
  11.                 cClass (){};
  12.         };
  13.         extern "C" cClass* cSayHello(cClass* cclass);
  14.     #else
  15.         /*End CPP header information */
  16.         ///////////////////////////////////
  17.         /*Start C Header Information */
  18.         typedef struct cClass {}cClass;
  19.     #endif    
  20.  
  21.     #ifdef __cplusplus
  22.         extern "C" 
  23.         {
  24.     #endif
  25.  
  26.  
  27.     void cSpeak(struct cClass* cclass);
  28.  
  29.     #ifdef __cplusplus
  30.         }
  31.     #endif
  32.     /* End C Header Information */    
  33.  
  34.  
  35. #endif //For Header.h define check.
  36.  
  37.  
cSource.c
Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. #include "header.h"
  3.  
  4.  
  5. void cSpeak(cClass* cclass)
  6. {
  7.     cSayHello(cclass);
  8. }
  9.  
  10.  
cppSource.cpp
Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. #include "header.h"
  3.  
  4. void cClass::sayHello() //This is the function we are trying to run from C
  5. {
  6.     printf ("This is how you say hello, using C that calls a C++ function");
  7. }
  8.  
  9. extern "C" cClass* cSayHello(cClass* cclass) //This returns a pointer for the C function!
  10. {
  11.     cclass->sayHello();
  12.     return cclass;
  13. }
  14.  
  15.  
cMain.c
Expand|Select|Wrap|Line Numbers
  1. //Includes
  2. #include <stdio.h>
  3. #include "header.h"
  4.  
  5. int main()
  6. {
  7.     cClass cclass;
  8.     printf ("void cSpeak(cClass* cclass);");
  9.     cSpeak(&cclass);
  10.     return 0;
  11. }
  12.  
  13.  

$>gcc -c cMain.c -o main.o
$>gcc -c cSource.c -o csource.o
$>g++ -c cppSource.cpp -o cppsource.o
$>gcc -o main.o csource.o cppsource.o //This gives the following error.

csource.o: In function `cSpeak':cSource.c:(.text+0xd): undefined reference to `cSayHello'
collect2: ld returned 1 exit status

Thanks for all the help in advance!
Mar 13 '09 #1
13 20355
weaknessforcats
9,208 Expert Mod 8TB
First, cClass is a C++ class and there are no classes in C so you can't create a cClass object in main().

You can call any C++ functions from C but you will have to be sure all of the C++ functions are in C++ source files and compiled as C++.

Any C++ functions called from C have to be extern "C" to surn off the C++ mangler. Therefore, you lose function oveloading, too.

So, to call cClass::sayHello from C you would in the C main():

1) call cSpeak(). No arguments.
This would be an extern "C" C++ function.
2) cSpeak would create a cClass object on the heap and call sayHello on that object.
3) cSpeak would delete the cClass object and return
Mar 13 '09 #2
wexx
24
@weaknessforcats
Oh i guess I should have mentioned about the wrapper thing I was looking to do. From my internet journey I have discovered a way to do it, by creating a wrapper function that returns a pointer to the class method. Here is the link i found. Its about the third sentence down "Naturally...." I somewhat understand what is going on, however I'm confused about where certain pieces go.

http://www.research.att.com/~bs/bs_faq2.html#callCpp
Mar 13 '09 #3
weaknessforcats
9,208 Expert Mod 8TB
You want to be careful here.

This is from your referenced article:
extern "C" double call_C_f(C* p, int i) // wrapper function
{
return p->f(i);
}
This function takes a C* and the member function is called using that pointer.
This is exactly what I said to do in my earlier post except without the C* argument:

Now C::f() can be used like this:
/* C code: */

double call_C_f(struct C* p, int i);

void ccc(struct C* p, int i)
{
double d = call_C_f(p,i);
/* ... */
}
Here an assumption is made: Namely the struct C has the same address as a class C. It's based on the fact that classes in C++ are really implemented as structs. Personally, I would remove the assumption by using a struct C* in the C function and on the C++ side using a struct C rather than a class C.

If you specify public/private/protected for every struct member, then a struct and a class are identical.

I so not know if this assumption is part of the C++ standard or whether it is compiler-dependent. Every time I have done this the class and the struct work the same in C++.

But were I coding this, ccc() would look like this:
Expand|Select|Wrap|Line Numbers
  1. void ccc(int arg)
  2. {
  3.      wrapperfunction(arg);   //a C++ function
  4. }
  5.  
where
Expand|Select|Wrap|Line Numbers
  1. void wrapperfunction(int arg)
  2. {
  3.     C* ptr = new C;
  4.          ptr->f(i);
  5.     delete C;
  6. }
  7.  
There's no need to pass a C* around onb the C side. You just stay in C++ until you can delete the C object.

That is, your C main() itself is just a wrapper for C++ and you should put all of your code in C++. Here's the C main():
Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3.     cplusplusmain();
  4. }
  5.  
where cplusplusmain() wraps the entire C++ application:
Expand|Select|Wrap|Line Numbers
  1. extern "C" int cplusplusmain()
  2. {
  3.     the ActualApplication();
  4. }
  5.  
theActualApplication is your C++ main().
Mar 13 '09 #4
wexx
24
This is exactly what I said to do in my earlier post except without the C* argument:
My apologies, I must have overlooked that small detail. I am having more trouble with the layout of where things go than with the theory behind it all. This is the most in depth I've ever gone with C or C++ for that matter.

If I have a common header, I get very confused where to add the extern "C" and where not to.

Lets see if I can sum this up properly:

If I am careful I can use a c++ class and a C struct (only if it's assumed the address are the same and the class is designed to mimic a struct), or I have a c++ struct and a c struct.

Then in cMain I call a function that is an extern "C" cppMain(), which then does all the work such as creating a class accessing its members and doing what needs to be done.

Where i get confused is what files go where in this case. If i have cMain.c, csource.c, cppsource.cpp, and header.h

Sorry for being so clumsy at this, but I've been trying to get my head around this (syntactically) most of this week, and I've confused myself pretty bad. Sadly it wouldn't be so bad if the examples from the sites I've been looking at would show how to link all these files together, and where the corresponding functions go.

The only two sites I have are :
http://www.parashift.com/c++-faq-lit....html#faq-32.8

and the one above.
Do you know of any other good resources for examples or information on what I'm trying to do?

I appreciate all your help weaknessforcats
Mar 13 '09 #5
weaknessforcats
9,208 Expert Mod 8TB
Do not use a common header. C ande C++ are different languages and you will have problems on the C side tripping over C++ syntax and troubles on the C++ side because C syntax can work differently (or be an outright error) on the C++ side.

Instead, have a C header for the C side and a C++ header for the C++ side.

The extern "C" goes into the C++ header since that is C++-only syntax.

Then your C code is in a .c file and that code includes your C header.

Your C++ code is in a .cpp file and that code includes your C++ header.

You compile each source file and then link the object files together to create your final executable.

Usually, this consists of having the .c and the .cpp files members of the same project. Then when you build, the .c files are compiled as C code and the .cpp files are compiled as C++ code. The link step takes care of linking the object files together. (this is how Visual Studio.NET does it).

Lastly, remember, that at the object level everything is binary and all notion od C or C++ is lost. All you need to do is get your source code to compile using the correct language.
Mar 14 '09 #6
wexx
24
Thanks so much weaknessforcats. I'm going to try this code and I'll let you know how everything works out and if i need more help. I'll post the results (the files and possibly a make file) so that anyone who has this question can have it answered with a good example.
Mar 16 '09 #7
wexx
24
I believe it worked. Can you check this to make sure it is indeed C calling C++? It would be greatly appreciated.

cMain.c
Expand|Select|Wrap|Line Numbers
  1. /* This is the C main file.  This should also be compiled with a c compiler */
  2. #include <stdio.h>         // This is included because printf is used.
  3. #include "cheader.h"     // We are calling functions from the C source here. so we
  4.                         //need the header for it.
  5.  
  6. int main()
  7. {
  8.     printf ("About to run the c function.\n");
  9.     cSpeak(); // Call the C function to start everything.
  10.     return 0;
  11. }
  12.  
  13.  

cheader.h
Expand|Select|Wrap|Line Numbers
  1. // This is the header file for all the C functions.
  2. // 
  3.  
  4. //Function to initiate the C++ function.
  5.  
  6. void cSpeak();
  7.  
  8.  

cppheader.h
Expand|Select|Wrap|Line Numbers
  1. //C++ Header, this is where all the C++ functions are prototyped. 
  2. //
  3.  
  4. // C++ class which holds the member function sayHello();
  5.  
  6. class myTest
  7. {
  8.     public:
  9.         void sayHello();
  10.         myTest(){};
  11. };
  12.  
  13. //Purpose of this function is to call sayHello
  14. //This function is also, C compatible. (because we used extern "C")
  15. extern "C" void sayHelloWrapper();
  16.  
  17.  
cppSource.cpp
Expand|Select|Wrap|Line Numbers
  1. /* This is the c++ source file.*/
  2. #include "cppheader.h" // Include the cppheader.h file
  3. #include <stdio.h> // We need to include this in order to use printf.
  4.  
  5. //This is the function we are trying to run from C (it needs a wrapper)
  6. void myTest::sayHello() 
  7. {
  8.     printf ("This is how you say hello, using C that calls a C++ function\n");
  9. }
  10.  
  11. //This function is meant to call the class function. This is the wrapper.
  12. extern "C" void sayHelloWrapper() 
  13. {
  14.     printf("inside wrapper about to run sayHello\n");
  15.     myTest* speak; // Create instance of class type 
  16.     speak->sayHello(); // call sayHello()
  17.  
  18. }
  19.  
  20. /*  This file needs to be compiled by the c++ compiler.  ie: g++ */
  21.  
cSource.c
Expand|Select|Wrap|Line Numbers
  1. /* This file is small for readibility. */
  2. #include "cheader.h" //Include the cheader.h file.  It contains the cSpeak() protoype
  3. #include <stdio.h> // We have to include this to use printf.
  4.  
  5. // C function designed to call a C++ function.
  6. void cSpeak()
  7. {
  8.     printf("Inside cspeak.. running wrapper.\n");
  9.     sayHelloWrapper();
  10. }
  11.  
  12. /* This file needs to be compiled by the C compiler. ie gcc -c */
  13.  
Makefile
Expand|Select|Wrap|Line Numbers
  1. #This simple make file must be executed from within the directory that contains
  2. #the source files, header files, and main files.
  3.  
  4. #linking of all the main .o files
  5. run : cMain.o cppSource.o cSource.o
  6.     g++ -o run cMain.o cppSource.o cSource.o
  7.  
  8. # c files need to be compiles with gcc
  9. cMain.o : cMain.c
  10.     gcc -c cMain.c
  11.  
  12. cSource.o : cSource.c
  13.     gcc -c cSource.c
  14.  
  15. # cpp files need to be compiled with g++
  16. cppSource.o : cppSource.cpp
  17.     g++ -c cppSource.cpp
  18. # this allows you to remove all the .o files from the directory in which you compiled
  19. # simply issue the command <make clean> and it will perform this action.    
  20. clean:
  21.     rm -f *.o
  22.  
Hopefully this helps everyone. Thanks again weaknessforcats, i appreciate it very much.

Plop all the files in a directory, and then run the make file. That should do it.
Mar 16 '09 #8
wexx
24
OK, so i got the variable passing down. But I decided that I need to be able to pass multiple objects back and forth, so I decided to use a structure.

In my CHeader file I have this:
Expand|Select|Wrap|Line Numbers
  1. typedef struct returnData
  2. {    
  3.  /*    This is the structure that gets changed for passing
  4. *    data back and forth from C and C++
  5.  */ 
  6.     char* txtResult;
  7.     int intResult;
  8.     int intMultiResult[50];
  9.     int resultToGet;
  10. };
  11. struct returnData* cData;
  12.  
  13. void getMachineInfoC();
  14.  
  15.  
in my CppHeader.h file i have this:
Expand|Select|Wrap|Line Numbers
  1. typedef struct returnData
  2. {    
  3. /*    This is the structure that gets changed for passing
  4. *    data back and forth from C and C++
  5.  */ 
  6.     char* txtResult;
  7.     int intResult;
  8.     int intMultiResult[50];
  9.     int resultToGet;
  10. };
  11. struct returnData* cppData;
  12.  
  13. extern "C" void getMachineInfoCpp(returnData* cppData, char* machineName);
  14.  
  15.  
Now, what i want to do is essentially pass the address from the C function to the C++ function. Do what I gotta do in C++ then output all the stuff using C


C Function Description
Expand|Select|Wrap|Line Numbers
  1. void getMachineInfoC()
  2. {
  3.  
  4.        char machineName[50];
  5.     printf ("Enter the name of the machine: ");
  6.     fgets(machineName, 50, stdin);
  7.     rmNewline(machineName, 50);
  8.     (*cData).intResult = 10;   //This causes a segfault 
  9.  
  10.     getMachineInfoCpp(&cData, &machineName[0]);
  11.  
  12.     //These print statements don't work either
  13.     printf ("Error Status: %d\n", cData->intMultiResult[0]);
  14.     printf ("Machine ID:   %d\n", cData->intMultiResult[1]);
  15.     printf ("MiltID:       %d\n", cData->intMultiResult[2]);
  16. }
  17.  
  18.  
CPP Function Description:
Expand|Select|Wrap|Line Numbers
  1. extern "C" void getMachineInfoCpp(returnData* cppData , char* machineName)
  2. {
  3.  
  4.     string query;
  5.     string query1 = "select * from sp_getmachineid('";
  6.     string query2 = (string)machineName;
  7.     string query3 = "');";
  8.     query = query1 + query2 + query3;
  9.     cout << query << endl;
  10.     startHandling(1);
  11.  
  12.     initConnection();
  13.  
  14.     icConnection.dbStatement->Execute(query);
  15.  
  16.     while (icConnection.dbStatement->Fetch())
  17.     {
  18.         (icConnection.dbStatement)->Get(1, cppData->intMultiResult[0]);
  19.         (icConnection.dbStatement)->Get(2, cppData->intMultiResult[1]);
  20.         (icConnection.dbStatement)->Get(3, cppData->intMultiResult[2]);
  21.     }
  22.     startHandling(0);
  23.     printf ("intResult %d", cppData->intResult);
  24.     printf("qResult 1: %d\n 2: %d\n 3: %d\n", 
  25.         cppData->intMultiResult[0],
  26.         cppData->intMultiResult[1], 
  27.         cppData->intMultiResult[2]);
  28. }
  29.  
Thank you all for your help. I know I'm probably just doing my pointer stuff incorrectly.
Apr 2 '09 #9
weaknessforcats
9,208 Expert Mod 8TB
This code:

Expand|Select|Wrap|Line Numbers
  1.  (*cData).intResult = 10;   //This causes a segfault  
should be written as:

Expand|Select|Wrap|Line Numbers
  1. cData->intResult = 10;   
That's a matter of style but is not your problem.

Your problem is that cData is a returnData* that does not point to a returnData variable. That is, it an uninitialized pointer.
Apr 2 '09 #10
wexx
24
Ahh, got it. THX!!!

But with pointers I have another concept. I tried a bunch of diferent methods but nothing i seem to try works to convert the value of qresult to qresultptr

Expand|Select|Wrap|Line Numbers
  1. char qResult[25];
  2. char* qResultptr;
  3.  
  4. //get a value for qResult[]
  5. //lets say qResult="superman"
  6.  
  7. qResultptr=qResult; // this doesn't work.  and strcpy segfaults.
  8.  
Apr 2 '09 #11
weaknessforcats
9,208 Expert Mod 8TB
It works for me:
Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3. char qResult[25]; 
  4. char* qResultptr; 
  5.  
  6. //get a value for qResult[] 
  7. //lets say qResult="superman" 
  8.  
  9. qResultptr=qResult; // this doesn't work.  and strcpy segfaults
  10. strcpy(qResultptr, "superman");
  11. cout << qResultptr << '\n'
  12.          << qResult << endl;
  13. }
Of course, this can't work:
Expand|Select|Wrap|Line Numbers
  1. qResult="superman" 
because the name of an array is the address of element 0 and this code attempts to change the address of qResult[0] (a local variable) and this you cannot do.
Apr 3 '09 #12
wexx
24
Ahh, you know I'm beginning to get the hang of all this complex (complex to me anyway) pointer logic. Thank you so much weaknessforcats.

I've got another question yet again. A tad more complex for me this time probably not for you.

OK so i call getDBVersionCpp from C and give it the pointer to an array of structures. Everything works fabulous. Here's the catch though. Once the aryResults is returned by the getDBVersionCpp, and I go to do the printf's, I get the correct value of gobble gobble from myResults[1].textResults[1] however, instead of getting 5.8.10 for the db version i get a strange symbol.

Everything on the CPP side prints out just as it should. The comments will show what it prints out.

Can anyone explain to me why this is happening?

cheader.h
Expand|Select|Wrap|Line Numbers
  1. typedef struct
  2. {
  3.     char* textResults[1024];
  4.     int intResults[1024];
  5.     int exitStatus;
  6. }results;
  7. results cResults[10];
  8. results* ptrResults;
  9. void rmNewline(char*, int);    // Function to remove the newline from the user's input.
  10. void getDBVersionC();        // Function to show the database version.
  11.  
cSource.c
Expand|Select|Wrap|Line Numbers
  1. void getDBVersionC()
  2. {
  3.     ptrResults = cResults;
  4.     results* myResults;
  5.     myResults = getDBVersionCpp(ptrResults);
  6.     printf("\n");
  7.     printf("Database Version: %s\n", myResults[1].textResults[2]); 
  8.            //prints ----- Database Version: <some symbol>   (wtf?)
  9.     printf("What is gibberish: %s\n", myResults[1].textResults[1]);
  10.            //prints ----- What is gibberish:  gobble gobble
  11.     getchar();
  12. }
  13.  
cppheader.h
Expand|Select|Wrap|Line Numbers
  1. #include "cheader.h"
  2. extern "C"
  3. {
  4.     results* getDBVersionCpp(results* aryResults);
  5. }
  6.  
  7.  
cppSource.cpp
Expand|Select|Wrap|Line Numbers
  1. extern "C"
  2. {
  3.     results* getDBVersionCpp(results* aryResults)
  4.     {    /* Function for getting the version of the database */
  5.         char qResult[25];
  6.         char* ptrTextResult;
  7.         char* gobble = "gobblegobble";
  8.         std::string query = "select cast(versionstring as varchar(25)) from version;";
  9.  
  10.         //startHandling(1);
  11.         initConnection();
  12.         icConnection.dbStatement->Execute(query);
  13.  
  14.         while (icConnection.dbStatement->Fetch())
  15.         {
  16.             (icConnection.dbStatement)->Get(1, qResult);
  17.         }
  18.         //startHandling(0);
  19.         cout << "*****************************************************"<<endl;
  20.         cout << "qResult: " << qResult << endl;   
  21.                        //prints ----- qResult: 5.8.10 (works great)
  22.         ptrTextResult = qResult;
  23.         cout << "ptrResult: " << ptrTextResult << endl;
  24.                        //prints ------ ptrResult: 5.8.10 (works great)
  25.         cout << "*****************************************************"<<endl;
  26.         aryResults[1].textResults[1] = gobble;
  27.         aryResults[1].textResults[2] = ptrTextResult;
  28.         cout << "CPP: cResults[1].textResults[2]: " << aryResults[1].textResults[2] << endl;
  29.                    // prints CPP   cResults[1].textResults[2]: 5.8.10 (works) 
  30.         cout << "CPP: cResults[1].textResults[1]: " << aryResults[1].textResults[1] << endl;
  31.                   // prints CPP: cResults[1].textResults[1]: gobble gobble (works)
  32.         cout << "*****************************************************"<<endl;
  33.         closeConnection();
  34.  
  35.         return (aryResults);
  36.     }
  37. }// End Extern "C"
  38.  
Apr 8 '09 #13
weaknessforcats
9,208 Expert Mod 8TB
typedef struct
{
char* textResults[1024];
int intResults[1024];
int exitStatus;
}results;
results cResults[10];
results* ptrResults;
This code says results is a type and that type is another name for that struct.

That's OK.

Next you create an array of results banking on that typedef.

That's OK.

Next you create a results* banking on that typedef.

That's OK.

Now to include this header again on the C++ side
thereby creating ANOTHER cResults array and ptrResults pointer.

That's NOT OK.

You never put code in a header file that allocates memory. When you do you get new variables every time you include that header.

So, remove
Expand|Select|Wrap|Line Numbers
  1. results cResults[10]; 
  2. results* ptrResults;  
from your header file and make them variables in your C main().

Change your function prototypes to have a result* argument. You call the function using the name of the array, cResults.

You don't need ptrResults.

Your function does not need to return a results* since you now pass it in.

Your C main() should look like:
Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3. results cResults[10]; 
  4. getDBVersionC(cResults);
Apr 9 '09 #14

Sign in to post your reply or Sign up for a free account.

Similar topics

0
by: George Vodpik | last post by:
Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Message-ID: <e1$RDGmfEHA.2200@TK2MSFTNGP09.phx.gbl> Newsgroups: microsoft.public.dotnet.general...
2
by: Jan | last post by:
Here's the code with the problem: class Startup { public static string Sym; public static string PrevDate; public static int Highest = new int; // ______________
7
by: JJ | last post by:
Hi, I call a class in my windows service app and in that class I access a method that returns an OleDbReader. Now It does have records in the reader when I step through the method but when I...
5
by: Nick Flandry | last post by:
I'm running into an Invalid Cast Exception on an ASP.NET application that runs fine in my development environment (Win2K server running IIS 5) and a test environment (also Win2K server running IIS...
5
by: huzz | last post by:
I am trying to create instance of class and and call a method of this class that creates a global variable which is available in anywhere in the page.. Here is what i am doing.. but i am getting...
1
by: Rik | last post by:
Yes, it's the week of OO here in c.l.php If I want to call the method a class (not an object), one normally uses: classname::method(); which works fine. However, what if I don't know the...
4
by: ssg31415926 | last post by:
I want to write a logging method. I want it to log the name of the calling class and method. Is there any way to do this? I presume it'll use Reflection but it's not an area I've used much.a ...
6
by: Sagari | last post by:
Greetings, Can someone suggest an efficient way of calling method whose name is passed in a variable? Given something like: class X: #... def a(self):
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
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
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...

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.