已知大小的未指定类型的指针算法
Pointer arithmetic of unspecified type with known size
void * ptr = NULL; // array of unspecified 13-byte type
for (int i = 0; i < 10; i++) {
printf("%i ", ((char (*) [13]) ptr) + i);
}
putchar('\n');
输出:
0 13 26 39 52 65 78 91 104 117
所以这是有效的(至少在 GCC 上是这样)但是我如何声明一个 (char (*) [13]
类型的变量,这样我就不必每次都在该指针上执行指针算术时进行强制转换?
这种行为是否可移植?
你的意思好像是下面这样
char s[10][13];
//…
void * ptr = s;
用作初始值设定项的数组 s
被隐式转换为指向类型 char ( * )[13]
.
的第一个元素的指针
或者你可以这样写
char s[10][13];
//…
char ( *tmp )[13] = s;
void * ptr = tmp;
这是一个演示指针运算的演示程序
#include <stdio.h>
int main(void)
{
enum { N = 13 };
char s[][N] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
const size_t M = sizeof( s ) / sizeof( *s );
void * ptr = s;
for ( size_t i = 0; i < M; i++ )
{
printf( "%s ", ( ( char ( * )[N] )ptr )[i] );
// or
// printf( "%s ", *( ( char ( * )[N] )ptr + i ) );
}
putchar( '\n' );
return 0;
}
它的输出是
A B C D E F G H I J
你是什么意思? ptr
甚至没有分配。转换它会导致未定义的行为。
您可以这样做
void * ptr = malloc(10 * 13); // on heap
或者这个
void * ptr = (char [10][13]){}; // on stack (C99)
Pointer arithmetic of unspecified type with known size
And is this behavior even portable?
严格来说:可能:
需要深入了解 C17 6.3.2.3 Pointers
类似下面的内容依赖于 &fred[0]
的值能够毫无问题地转换为 ptr
。许多实现都可以毫无问题地处理这个问题,但是 ptr
是指向数组的指针,而不是指向 char
的指针。如果 ptr
是指向 char
的指针,没问题。
我 认为 因为 ptr
和 fred
都有相同的对齐要求 - 代码没问题。
typedef something unspecified_13_byte_type;
assert(sizeof(unspecified_13_byte_type) == 13);
#define N
unspecified_13_byte_type fred[N];
char (*ptr)[13] = (void *) fred;
for (int i = 0; i < N; i++) {
// printf("%i ", ((char (*) [13]) ptr) + i);
printf("%p ", (void *) (((char (*) [13]) ptr) + i));
}
puts("");
更深:如果 something
是一些 struct
,那么 ptr
和 &fred[0]
不需要相同的编码甚至相同的大小 - 即使它们很好地转换彼此来来去去,彼此等同。 struct
指针和 char *
可能比通常预期的更加不同 - 即使这种差异在今天非常罕见。
void * ptr = NULL; // array of unspecified 13-byte type
for (int i = 0; i < 10; i++) {
printf("%i ", ((char (*) [13]) ptr) + i);
}
putchar('\n');
输出:
0 13 26 39 52 65 78 91 104 117
所以这是有效的(至少在 GCC 上是这样)但是我如何声明一个 (char (*) [13]
类型的变量,这样我就不必每次都在该指针上执行指针算术时进行强制转换?
这种行为是否可移植?
你的意思好像是下面这样
char s[10][13];
//…
void * ptr = s;
用作初始值设定项的数组 s
被隐式转换为指向类型 char ( * )[13]
.
或者你可以这样写
char s[10][13];
//…
char ( *tmp )[13] = s;
void * ptr = tmp;
这是一个演示指针运算的演示程序
#include <stdio.h>
int main(void)
{
enum { N = 13 };
char s[][N] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
const size_t M = sizeof( s ) / sizeof( *s );
void * ptr = s;
for ( size_t i = 0; i < M; i++ )
{
printf( "%s ", ( ( char ( * )[N] )ptr )[i] );
// or
// printf( "%s ", *( ( char ( * )[N] )ptr + i ) );
}
putchar( '\n' );
return 0;
}
它的输出是
A B C D E F G H I J
你是什么意思? ptr
甚至没有分配。转换它会导致未定义的行为。
您可以这样做
void * ptr = malloc(10 * 13); // on heap
或者这个
void * ptr = (char [10][13]){}; // on stack (C99)
Pointer arithmetic of unspecified type with known size
And is this behavior even portable?
严格来说:可能:
需要深入了解 C17 6.3.2.3 Pointers
类似下面的内容依赖于 &fred[0]
的值能够毫无问题地转换为 ptr
。许多实现都可以毫无问题地处理这个问题,但是 ptr
是指向数组的指针,而不是指向 char
的指针。如果 ptr
是指向 char
的指针,没问题。
我 认为 因为 ptr
和 fred
都有相同的对齐要求 - 代码没问题。
typedef something unspecified_13_byte_type;
assert(sizeof(unspecified_13_byte_type) == 13);
#define N
unspecified_13_byte_type fred[N];
char (*ptr)[13] = (void *) fred;
for (int i = 0; i < N; i++) {
// printf("%i ", ((char (*) [13]) ptr) + i);
printf("%p ", (void *) (((char (*) [13]) ptr) + i));
}
puts("");
更深:如果 something
是一些 struct
,那么 ptr
和 &fred[0]
不需要相同的编码甚至相同的大小 - 即使它们很好地转换彼此来来去去,彼此等同。 struct
指针和 char *
可能比通常预期的更加不同 - 即使这种差异在今天非常罕见。