简体   繁体   中英

Function scope regarding pointers in C++ (or C)

I am attempting to write portable code that allows the function to access a variable like an array, even if it is just a single value. The idea behind it is that the code will not make an array of size 1, but I need to be able to loop over all the values in the array if it is an array. Since I can't use sizeof(foo) to determine whether the memory is larger than a single instance sizeof(foo)/sizeof(int) might work, but it is too cumbersome to include in the main code. Macros wouldn't help because if I used a ternary operator like I'd expect #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo) #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo) to return a pointer, in order to access with indexing. This problem is the compiler doesn't like the mixing of types between pointers and non-pointers.

So my second attempt was function overloading.

int * convert(int value)
    {return &value;}
int * convert(int * value)
    {return value;}

I know that this wouldn't work, because the first function would return the address of the temporary variable copy in that function scope. So my third attempt was

int * convert(int * value)
    {return value;}
int * convert(int ** value)
    {return *value;}

Every time I would call convert, pass the address of the value: convert(&foo) . This should work, and (I think) it avoids returning a temporary function scope address. The result of convert would be accessible with indexing. In a controlled for loop, the code would run smoothly. The program would know how many elements are in value, but it would be faster to run everything inside a for loop than not.

So why does my second block of code produce the "Warning returning temporary scope blahblahblah" warning?

UPDATE: Major XY problem here.

Basically I'm trying to wrap all my code in a loop and access each value in a variable, one value per loop iteration. The system would know how many values are in that variable, but the code base is so large that wrapping everything in an if/else would be slow. So the way to access some value in the for loop with an index would be int foo = convert(&maybeArray)[counter]; Then I would use foo several times in the for loop. For some reason Visual Studio was throwing an error while with the second block of code. Added this to OP.

Another solution would be to make 2 functions with overloaded operators that would basically execute the entire code, without converting each variable, but the code base is very large, and this needs to be as portable as possible. Referencing convert would be more future proof I would believe.

You've tagged this as C++ , so I'm assuming you are using a C++ compiler.

There's a lot going on in your question, so I'm going to simplify. You want a C++ function convert(x) that will:

  1. if x is an array, return the address of the first element
  2. if x is not an array, return &x .

(Generally, maybe you need to redesign this whole thing, convert seems like a pretty strange function to want).

template<typename T, size_t N>
auto convert(  T (&t) [N] ) -> T* {
    return t; // just let pointer decay work for us here
}
template<typename T>
auto convert( T &t) -> T* {
    return &t;
}

And, in C++, I would never use sizeof with things that I think are arrays. This template technique is a safer way to count the number of elements in an array.

Also, do you expect to have arrays of pointers, and to want to treat a single pointer as a single-element-array of pointers? If so, then tread carefully. Something that looks like an array, might actually be a pointer, eg arrays in parameter lists foo(int is_really_a_pointer[5]) { ...} . See the comment by @MSalters for more. Might be good to use his assert to catch any surprises. If you're just using int , then don't use the typename T in my templates, just force it to be int for clarity.

Finally, maybe instead of turning arrays into pointers, you should ask for a function that turns a non-array into a reference to a single-element array?

Update Here is a more complete example showing how to use convert and convert_end to find the beginning and end of an array to iterate over all the elements in an array; where, of course, a non-array is treated as an array of one element.

In C, there exist only pass by value. When you pass a pointer to a function then its address is copied to the function parameter. This simply means that if p is a pointer in calling function then a function call

int x = 5;
int *p = &x;
int a = foo(p);   

for function definition

int foo(int *p1)
{
    return *p1*2;
}  

is implies that:

  • copy the address p points to parameter p1 , ie make p and p1 points to the same location.
  • any changes to the location pointed by p1 in function foo is reflected to *p because p and p1 is pointing to same location. But, if at any point p1 points to another location then this does not imply that p will point to that location too. p and p1 are two different pointers.

When you you pass a pointer to pointer, as in your last snippet of second block,

int * convert(int ** value)
{return *value;}  

if *value changes to points to different location after argument is passed to it, then that pointer whose address is passed will also be updated with this location. In this case no need to return *value , but returning do no harm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM