我应该创建一个变量
long long hex = 0x1a1b2a2b3a3b4a4bULL;
然后定义指向1a1b,2a2b,3a3b和4a4b的4个指针。然后我打印那些双字节的地址和值。
我的方法是创建一个指针
long long *ptr1 = &hex;
然后使用指针算法来获取下一个值。我意识到增加这个指针会增加长字节,而不是像我需要的那样增加2个字节。创建一个短指针
short *ptr1 = &hex;
我需要什么,但我的编译器不会让我,因为数据类型不兼容。我该如何解决这个问题?有没有办法创建一个递增2个字节的指针并将其分配给更大数据类型的变量?
答案 0 :(得分:8)
您只能通过兼容类型访问任何变量。
但是,char
指针可用于访问任何类型的变量。
请不要将 投射到short*
请参阅下面的注释,它们不是兼容类型。您只能使用char*
来验证代码。
引用C11
,章节§6.3.2.3
[...]当指向对象的指针转换为指向字符类型的指针时, 结果指向对象的最低寻址字节。连续增量 结果,直到对象的大小,产生指向对象剩余字节的指针。
所以,出路是,使用char *
并使用指针算法来获取所需的地址。
注意:由于所有其他答案都提示了一个明显错误的方法(将指针强制转换为显式违反严格别名的short *
),让我对我的答案和支持引号进行扩展。
引用C11
,章节§6.5/ P7
对象的存储值只能由具有其中一个的左值表达式访问 以下类型: 88)
- 与对象的有效类型兼容的类型,
- 与对象的有效类型兼容的类型的限定版本
- 对应于有效类型的有符号或无符号类型 对象,
- 对应于合格版本的有符号或无符号类型的类型 有效的对象类型,
- 包含其中一种上述类型的聚合或联合类型 成员(包括,递归地,子集合或包含的联合的成员),或
- 字符类型。
在这种情况下,short
和long long
不是兼容类型。所以唯一的出路是使用pointer to
char`类型。
这是OP的更新
编辑: 这是不会导致未定义行为的正确解决方案。 编辑2: 添加了内存地址。
#include <stdio.h>
int main() {
long long hex = 0x1a1b2a2b3a3b4a4bULL;
char *ptr = (char*)&hex;
int i; int j;
for (i = 1, j = 0; i < 8, j < 7; i += 2, j += 2) {
printf("0x%hx%hx at address %p \n", ptr[i], ptr[j], (void *) ptr+i);
}
return 0;
}
答案 1 :(得分:2)
正如所料,已经指出这是未定义的行为。这可能是这些愚蠢的“C课程”作业之一,其中C尚未被完全理解。
如果您想避开UB,可以使用union
来解决它:
#include <stdio.h>
union longparts
{
unsigned long long whole;
unsigned short parts[4];
};
int main(void)
{
union longparts test;
test.whole = 0x1a1b2a2b3a3b4a4bULL;
for (int i = 0; i < 4; ++i)
{
unsigned short *part = &test.parts[i];
printf("short at addr %p: 0x%hx\n", (void *)part, *part);
}
return 0;
}
来自C11§6.5.2.3,脚注95:
如果用于读取union对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的相应部分将被重新解释为对象表示形式。 6.2.6中描述的新类型(有时称为''punning''的过程)。这可能是陷阱表示。
因此,在某些情况下,使用陷阱表示仍可能遇到问题,但至少它没有未定义。结果是实现定义,例如因为主机的字节顺序。
答案 2 :(得分:1)
添加演员:
short *ptr1 = (short*)&hex;
但是,请务必注意平台的This is the entire slide。 例如,在x86上,数据首先存储在最后,所以
ptr1[0]
应指向0x4a4b
还要注意你的平台实际尺寸:long long至少是64bit,short是至少16位。如果您想确保类型确实是那些尺寸,请使用uint64_t
和uint16_t
。如果没有与您系统上可用的确切大小相匹配的任何类型,您将收到编译器错误。
此外,请注意对齐。您可以将uint64_t
用作uint16_t[4]
,但不能相反,因为uint16_t
的地址通常可以分为两个,uint64_t
的地址可以分为8 {{1}}
答案 3 :(得分:0)
int main() {
long long hex = 0x1a1b2a2b3a3b4a4bULL;
short *ptr1 = (short*)&hex;
return 0;
}
这通常是一个警告,你可能有&#34; Werror&#34;编译器标志。
答案 4 :(得分:0)
您需要转换指针以将其指定为其他类型:
I wondered if it was possible to force Scala to use ForkJoinPool with a preset number of threads decided by us GLOBALLY
但是,这样做会导致实现定义的行为,因为您依赖于系统的字节顺序。