C++(或 C)中关于指针的函数作用域
Function scope regarding pointers in C++ (or C)
我正在尝试编写可移植代码,允许函数像数组一样访问变量,即使它只是单个值。它背后的想法是代码不会生成大小为 1 的数组,但如果它是一个数组,我需要能够遍历数组中的所有值。由于我不能使用sizeof(foo)
来判断内存是否大于单个实例sizeof(foo)/sizeof(int)
可能会起作用,但在主代码中包含它太麻烦了。宏不会有帮助,因为如果我使用三元运算符,我希望 #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo)
到 return 一个指针,以便通过索引访问。这个问题是编译器不喜欢指针和非指针之间的类型混合。
所以我的第二次尝试是函数重载。
int * convert(int value)
{return &value;}
int * convert(int * value)
{return value;}
我知道这行不通,因为第一个函数会 return 在该函数范围内复制临时变量的地址。所以我的第三次尝试是
int * convert(int * value)
{return value;}
int * convert(int ** value)
{return *value;}
每次调用 convert 时,传递值的地址:convert(&foo)
。
这应该有效,并且(我认为)它避免了 returning 临时函数范围
地址。 convert 的结果可以通过索引访问。在受控的 for 循环中,代码会 运行 顺利。该程序会知道有多少元素在值中,但是 运行 循环中的所有内容比不循环更快。
那么为什么我的第二个代码块会产生 "Warning returning temporary scope blahblahblah" 警告?
更新:此处存在主要 XY 问题。
基本上我试图将我的所有代码包装在一个循环中并访问一个变量中的每个值,每个循环迭代一个值。系统会知道该变量中有多少个值,但代码库太大,将所有内容包装在 if/else 中会很慢。因此,使用索引在 for 循环中访问某些值的方法是 int foo = convert(&maybeArray)[counter];
然后我会在 for 循环中多次使用 foo。
出于某种原因 Visual Studio 在处理第二个代码块时抛出错误。将此添加到 OP。
另一种解决方案是制作 2 个具有重载运算符的函数,这些函数基本上可以执行整个代码,无需转换每个变量,但代码库非常大,这需要尽可能可移植。我相信引用 convert
会更有前途。
在C语言中,只存在值传递。当您将指针传递给函数时,它的地址将被复制到函数参数中。这只是意味着如果 p
是调用函数中的指针,那么函数调用
int x = 5;
int *p = &x;
int a = foo(p);
用于函数定义
int foo(int *p1)
{
return *p1*2;
}
表示:
- 复制地址
p
指向参数p1
,即使p
和p1
指向同一个位置。
- 函数 foo 中
p1
指向的位置的任何更改都会反映到 *p
,因为 p
和 p1
指向相同的位置。但是,如果在任何时候 p1
指向另一个位置,那么这并不意味着 p
也会指向那个位置。 p
和 p1
是两个不同的指针。
当您将指针传递给指针时,就像在第二个块的最后一个片段中一样,
int * convert(int ** value)
{return *value;}
如果*value
在参数传递给它之后更改为指向不同的位置,那么其地址被传递的指针也将使用该位置进行更新。在这种情况下不需要 return *value
,但是 return 并没有什么坏处。
您已将此标记为 C++
,因此我假设您使用的是 C++ 编译器。
你的问题涉及很多,所以我将简化一下。你想要一个 C++ 函数 convert(x)
它将:
- if
x
is an array, return the address of the first element
- if
x
is not an array, return &x
.
(通常,您可能需要重新设计整个东西,convert
似乎是一个非常奇怪的功能)。
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;
}
而且,在 C++ 中,我永远不会将 sizeof
用于 我认为 是数组的东西。这种模板技术是计算数组中元素数量的一种更安全的方法。
此外,您是否希望拥有指针数组,并希望将单个指针视为指针的单元素数组?如果是这样,请谨慎行事。一些看起来像数组的东西,实际上可能是一个指针,例如参数列表中的数组 foo(int is_really_a_pointer[5]) { ...}
。有关更多信息,请参阅@MSalters 的评论。使用他的断言来捕捉任何惊喜可能会很好。如果您只是使用 int
,那么请不要在我的模板中使用 typename T
,为了清楚起见,只需将其强制为 int
。
最后,也许您不应该将数组转换为指针,而应该请求一个将非数组转换为对单元素数组的引用的函数?
Update 这里有一个 more complete example 展示了如何使用 convert
和 convert_end
找到数组的开头和结尾以遍历数组中的所有元素;当然,其中非数组被视为一个元素的数组。
我正在尝试编写可移植代码,允许函数像数组一样访问变量,即使它只是单个值。它背后的想法是代码不会生成大小为 1 的数组,但如果它是一个数组,我需要能够遍历数组中的所有值。由于我不能使用sizeof(foo)
来判断内存是否大于单个实例sizeof(foo)/sizeof(int)
可能会起作用,但在主代码中包含它太麻烦了。宏不会有帮助,因为如果我使用三元运算符,我希望 #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo)
到 return 一个指针,以便通过索引访问。这个问题是编译器不喜欢指针和非指针之间的类型混合。
所以我的第二次尝试是函数重载。
int * convert(int value)
{return &value;}
int * convert(int * value)
{return value;}
我知道这行不通,因为第一个函数会 return 在该函数范围内复制临时变量的地址。所以我的第三次尝试是
int * convert(int * value)
{return value;}
int * convert(int ** value)
{return *value;}
每次调用 convert 时,传递值的地址:convert(&foo)
。
这应该有效,并且(我认为)它避免了 returning 临时函数范围
地址。 convert 的结果可以通过索引访问。在受控的 for 循环中,代码会 运行 顺利。该程序会知道有多少元素在值中,但是 运行 循环中的所有内容比不循环更快。
那么为什么我的第二个代码块会产生 "Warning returning temporary scope blahblahblah" 警告?
更新:此处存在主要 XY 问题。
基本上我试图将我的所有代码包装在一个循环中并访问一个变量中的每个值,每个循环迭代一个值。系统会知道该变量中有多少个值,但代码库太大,将所有内容包装在 if/else 中会很慢。因此,使用索引在 for 循环中访问某些值的方法是 int foo = convert(&maybeArray)[counter];
然后我会在 for 循环中多次使用 foo。
出于某种原因 Visual Studio 在处理第二个代码块时抛出错误。将此添加到 OP。
另一种解决方案是制作 2 个具有重载运算符的函数,这些函数基本上可以执行整个代码,无需转换每个变量,但代码库非常大,这需要尽可能可移植。我相信引用 convert
会更有前途。
在C语言中,只存在值传递。当您将指针传递给函数时,它的地址将被复制到函数参数中。这只是意味着如果 p
是调用函数中的指针,那么函数调用
int x = 5;
int *p = &x;
int a = foo(p);
用于函数定义
int foo(int *p1)
{
return *p1*2;
}
表示:
- 复制地址
p
指向参数p1
,即使p
和p1
指向同一个位置。 - 函数 foo 中
p1
指向的位置的任何更改都会反映到*p
,因为p
和p1
指向相同的位置。但是,如果在任何时候p1
指向另一个位置,那么这并不意味着p
也会指向那个位置。p
和p1
是两个不同的指针。
当您将指针传递给指针时,就像在第二个块的最后一个片段中一样,
int * convert(int ** value)
{return *value;}
如果*value
在参数传递给它之后更改为指向不同的位置,那么其地址被传递的指针也将使用该位置进行更新。在这种情况下不需要 return *value
,但是 return 并没有什么坏处。
您已将此标记为 C++
,因此我假设您使用的是 C++ 编译器。
你的问题涉及很多,所以我将简化一下。你想要一个 C++ 函数 convert(x)
它将:
- if
x
is an array, return the address of the first element- if
x
is not an array, return&x
.
(通常,您可能需要重新设计整个东西,convert
似乎是一个非常奇怪的功能)。
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;
}
而且,在 C++ 中,我永远不会将 sizeof
用于 我认为 是数组的东西。这种模板技术是计算数组中元素数量的一种更安全的方法。
此外,您是否希望拥有指针数组,并希望将单个指针视为指针的单元素数组?如果是这样,请谨慎行事。一些看起来像数组的东西,实际上可能是一个指针,例如参数列表中的数组 foo(int is_really_a_pointer[5]) { ...}
。有关更多信息,请参阅@MSalters 的评论。使用他的断言来捕捉任何惊喜可能会很好。如果您只是使用 int
,那么请不要在我的模板中使用 typename T
,为了清楚起见,只需将其强制为 int
。
最后,也许您不应该将数组转换为指针,而应该请求一个将非数组转换为对单元素数组的引用的函数?
Update 这里有一个 more complete example 展示了如何使用 convert
和 convert_end
找到数组的开头和结尾以遍历数组中的所有元素;当然,其中非数组被视为一个元素的数组。