通常使用隐式函数返回void *转换来指定带有分配的指针,就像malloc()一样:
void *malloc(size_t size);
int *pi = malloc(sizeof *pi);
我希望在传递目标指针的地址时执行相同的赋值,而不从函数内部(不在其体内,也不在参数中)显式地转换它的类型。
以下代码似乎实现了这一点。
- 我想知道代码是否完全符合(任何)
C标准。
- 如果它不符合,我想知道是否可能
满足我的要求,同时符合(任何)C标准。
。
#include <stdio.h>
#include <stdlib.h>
int allocate_memory(void *p, size_t s) {
void *pv;
if ( ( pv = malloc(s) ) == NULL ) {
fprintf(stderr, "Error: malloc();");
return -1;
}
printf("pv: %p;\n", pv);
*((void **) p) = pv;
return 0;
}
int main(void) {
int *pi = NULL;
allocate_memory(&pi, sizeof *pi);
printf("pi: %p;\n", (void *) pi);
return 0;
}
结果:
pv: 0x800103a8;
pi: 0x800103a8;
不,这不合规。你通过了 int**
如 void*
(好的),但是你投了 void*
到了 void**
不保证具有相同的大小和布局。你只能取消引用一个 void*
(除了一个人来自 malloc
/calloc
)将它转换回原来的指针类型后,此规则不会递归应用(所以a void**
不会自动转换,就像一个 void*
)。
我也没有办法满足你的所有要求。如果必须通过指针传递指针,则需要实际传递a的地址 void*
在这种情况下,在调用者中进行所有必要的转换 main
。那就是
int *pi;
void *pv;
allocate_memory(&pv, sizeof(int));
pi = pv;
......打败你的计划
类型 int**
和 void**
不兼容
您正在将其实际类型为int **的p转换为void **,然后在此处取消引用它:
*((void **) p) = pv;
这将破坏别名规则。
您可以传递一个void指针然后正确地转换它:
void *pi = NULL;
int* ipi = NULL ;
allocate_memory(&pi, sizeof *ipi );
ipi = pi ;
或返回一个void指针。
int *pi = allocate_memory(sizeof *pi);
可以选择使用联合:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
union Pass
{
void** p ;
int** pi ;
} ;
int allocate_memory(union Pass u , size_t s) {
void *pv;
if ( ( pv = malloc(s) ) == NULL ) {
fprintf(stderr, "Error: malloc();");
return -1;
}
printf("pv: %p;\n", pv);
*(u.p) = pv;
return 0;
}
int main()
{
int* pi = NULL ;
printf("%p\n" , pi ) ;
allocate_memory( ( union Pass ){ .pi = &pi } , sizeof( *pi ) ) ;
printf("%p\n" , pi ) ;
return 0;
}
据我了解,这个例子符合标准。
使用静态断言来保证大小和对齐方式相同。
_Static_assert( sizeof( int** ) == sizeof( void** ) , "warning" ) ;
_Static_assert( _Alignof( int** ) == _Alignof( void** ) , "warning" ) ;
我认为不可能以100%符合标准的方式进行,因为不能保证非void指针的大小与 void*
。
这与标准要求明确铸造的原因相同 printf("%p")
参数 void*
。
我认为您的代码可能会提供一些有趣的问题,因为将void *转换为void **并取消引用它。根据海湾合作委员会的说法,这不是一个问题,但有时候海湾合你可以试试
#include <stdio.h>
#include <stdlib.h>
int allocate_memory(void **p, size_t s) {
if ( ( *p = malloc(s) ) == NULL ) {
fprintf(stderr, "Error: malloc();");
return -1;
}
return 0;
}
int main(void) {
int *pi = NULL;
if ( allocate_memory((void**) &pi, sizeof *pi) == 0 ) {
printf("pi: %p;\n", (void *) pi);
}
return 0;
}
请注意,您必须在原始代码中进行投射 int**
至 void*
(隐式)然后显式转换为 void**
这可能真的让您的编译器感到困惑。可能还有一个 别名 问题是由于主要的事实 int *pi
被访问并分配了一个 void
指针。但是,快速扫描C11标准在这方面尚无定论(见 http://open-std.org/JTC1/SC22/WG14/)。