CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8

Thread: Pointer Madness

  1. #1
    Join Date
    Oct 2019
    Posts
    4

    Pointer Madness

    Way in over my head trying to pass a variable number of arguments ( pointers ) to a routine.

    Arguments are passed in pairs, the variable type and then its address. When passing variables of type int things work, but byte and long types fail.



    Usage

    Code:
          byte TestByte = 10;
          va_func(1, 0, &TestByte); // Fails
    
          int TestInt = 20;
          va_func(1, 1, &TestInt); // Works
    
          long TestLong = 30;
          va_func(1, 2, &TestLong ); // Fails


    Routine

    Code:
          va_func(int ArgCount, ... ); 
          { 
            va_list Args;  
    
            va_start(Args, ArgCount);           
    
              for (int I = 0; I < ArgCount; I += 2)        
              { 
    /*
    *           Argument type
    */
                int VarType;
                VarType = va_arg(Args, int)
                printf("Type %d\n", VarType ); 
    /*
    *           Argument address
    */
                long VarAddress;
                VarAddress = va_arg(Args, int)
                printf("Address %d\n", VarAddress); 
    /*
    *           Argument Value
    */
                void *Ptr;
                Ptr = (void *)VarAddress;
                printf("Value %d\n", *Ptr);
    
    
                .....Code to process arguments goes here, returning a new value (NewValue) 
    
                *Ptr = NewValue;
    
              }
    
            va_end(Args);
    
          }

  2. #2
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,825

    Re: Pointer Madness

    for va_arg(), you need to know the type of the argument for the 2nd parameter. It won't auto-detect. That's why, for example, in printf() you have to specify the type of each of the arguments in the format string - so that the correct usage of va_arg() is used to correctly obtain the value for each argument.

    That's why as you are using int for va_arg(), the code only works when an int is passed.

    Are you using c or c++? If c++, then it would be better to use templated variadic arguments. See https://en.cppreference.com/w/cpp/la...parameter_pack
    Last edited by 2kaud; October 3rd, 2019 at 08:46 AM. Reason: Changed web reference
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #3
    Join Date
    Oct 2019
    Posts
    4

    Re: Pointer Madness

    I was thinking along those lines but was tripping up on the fact that I'm passing in pointers or addresses not values.

    I assumed that by passing addresses they would all be of the same length / number of bytes based on the OS, a 32 bit OS would push four bytes on the stack no matter what the data type of the variable being passed. Or so I thought.

    With addresses on the stack, not values, wouldn't va_arg always grab a 'pointers size' worth of data?



    As for the language, C or C++, I'm not completely sure. I'm using AVR-GCC for micro controllers / embedded systems.

  4. #4
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,825

    Re: Pointer Madness

    You can do this:

    Code:
    void va_func(int ArgCount, ...)
    {
    	va_list Args;
    
    	va_start(Args, ArgCount);
    
    	for (int I = 0; I < ArgCount; I += 2)
    	{
    		//Argument type
    		const int VarType = va_arg(Args, int);
    		printf("Type %d\n", VarType);
    
    		//Argument address
    		const void* VarAddress = va_arg(Args, void*);
    		printf("Address %p\n", VarAddress);
    
    		//Argument Value
    		printf("Value %hhi\n", *(char*)VarAddress);
    	}
    
    	va_end(Args);
    }
    
    int main()
    {
    	char TestByte = 10;
    	va_func(1, 0, &TestByte);
    
    	int TestInt = 20;
    	va_func(1, 1, &TestInt);
    
    	long TestLong = 30;
    	va_func(1, 2, &TestLong);
    }
    which displays on my computer:

    Code:
    Type 0
    Address 0018FF3F
    Value 10
    Type 1
    Address 0018FF38
    Value 20
    Type 2
    Address 0018FF34
    Value 30
    BUT for the argument value, you need to know the type of the argument for the appropriate cast. It works here as the cast is to char and the values are all within the char range. However, if the value for the int and long were outside of the char range then it wouldn't. If you are using c++, that's why variadic templated functions are better.

    PS
    As a value referring to the type is passed as the first arg of the pair following the initial number of pairs value, consider:

    Code:
    void va_func(int ArgCount, ...)
    {
    	va_list Args;
    
    	va_start(Args, ArgCount);
    
    	for (int I = 0; I < ArgCount; I += 2)
    	{
    		//Argument type
    		const int VarType = va_arg(Args, int);
    		printf("Type %d\n", VarType);
    
    		//Argument address
    		const void* VarAddress = va_arg(Args, void*);
    		printf("Address %p\n", VarAddress);
    
    		//Argument Value
    		switch (VarType) {
    			case 0:
    				printf("Value %hhi\n", *(char*)VarAddress);
    				break;
    
    			case 1:
    				printf("Value %i\n", *(int*)VarAddress);
    				break;
    
    			case 2:
    				printf("Value %li\n", *(long*)VarAddress);
    				break;
    
    			default:
    				printf("Unknown type %i\n", VarType);
    				break;
    		}
    	}
    
    	va_end(Args);
    }
    
    int main()
    {
    	char TestByte = 10;
    	va_func(1, 0, &TestByte);
    
    	int TestInt = 2000;
    	va_func(1, 1, &TestInt);
    
    	long TestLong = 300000000;
    	va_func(1, 2, &TestLong);
    }
    which as expected displays:

    Code:
    Type 0
    Address 0018FF37
    Value 10
    Type 1
    Address 0018FF38
    Value 2000
    Type 2
    Address 0018FF3C
    Value 300000000
    Last edited by 2kaud; October 3rd, 2019 at 10:22 AM. Reason: PS
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  5. #5
    Join Date
    Oct 2019
    Posts
    4

    Re: Pointer Madness

    I'm starting to think I'm dealing with a compiler issue, no matter what I try I can't get this to work. I went with long vs int to see if the long variable would work knowing full well that it would break the int version, but still no go.

    I tried using the code provided by 2kaud, thanks by the way, but the compiler doesn't like the syntax.

    When trying to use va_arg with the data type of byte the compiler gets mad.

    'byte {aka unsigned char}' is promoted to 'int' when passed through '...'

    Which has me thinking that the compiler is always defaulting to int which would explain why its the only data type that works - heck, I don't know whats going on, such a bummer.

  6. #6
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,825

    Re: Pointer Madness

    What compiler are you using? The code posted in #4 compiles OK and runs producing the given output using MS VS 2019.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  7. #7
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,825

    Re: Pointer Madness

    Well for VS 2019, extending this scheme to also allow double consider:

    Code:
    void va_func(int ArgCount, ...)
    {
    	va_list Args;
    	va_start(Args, ArgCount);
    
    	for (int I = 0; I < ArgCount; ++I) {
    		//Argument type
    		const int VarType = va_arg(Args, int);
    		//printf("Type %d\n", VarType);
    
    		//Argument address
    		const void* VarAddress = va_arg(Args, void*);
    		//printf("Address %p\n", VarAddress);
    
    		//Argument Value
    		switch (VarType) {
    			case 0:
    				printf("Value %hhi\n", *(char*)VarAddress);
    				break;
    
    			case 1:
    				printf("Value %i\n", *(int*)VarAddress);
    				break;
    
    			case 2:
    				printf("Value %li\n", *(long*)VarAddress);
    				break;
    
    			case 3:
    				printf("Value %f\n", *(double*)VarAddress);
    				break;
    
    			default:
    				printf("Unknown type %i\n", VarType);
    				break;
    		}
    	}
    
    	va_end(Args);
    }
    
    int main()
    {
    	const char TestByte = 10;
    	const int TestInt = 2000;
    	const long TestLong = 300000000;
    	const double testDouble = 3.14159;
    
    	va_func(4, 0, &TestByte, 1, &TestInt, 2, &TestLong, 3, &testDouble);
    }
    which for me displays:

    Code:
    Value 10
    Value 2000
    Value 300000000
    Value 3.141590
    as expected.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  8. #8
    Join Date
    Oct 2019
    Posts
    4

    Re: Pointer Madness

    Yea um - I'm using AVR-GCC for micro controllers / embedded systems.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured