有人可以解释为什么我没有得到变量的值,而是它的内存而不是?
我需要使用void*来指向"unsigned short"值.
正如我理解的无效指针,它们的大小是未知的,它们的类型是未知的.
然而,一旦初始化它们,它们是已知的,对吧?
为什么我的printf语句打印错误的值?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(int a, void *res){
res = &a;
printf("res = %d\n", *(int*)res);
int b;
b = * (int *) res;
printf("b =%d\n", b);
}
int main (int argc, char* argv[])
{
//trial 1
int a = 30;
void *res = (int *)a;
func(a, res);
printf("result = %d\n", (int)res);
//trial 2
unsigned short i = 90;
res = &i;
func(i, res);
printf("result = %d\n", (unsigned short)res);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到的输出:
res = 30
b =30
result = 30
res = 90
b =90
result = 44974
Run Code Online (Sandbox Code Playgroud)
要记住一件事:C不保证int足够大以容纳指针(包括void*).演员阵容不是一个便携式的东西/好主意.使用%p到printf的指针.
同样地,你在这里做了一个"糟糕的演员":void* res = (int*) a告诉编译器:"我确信它的值a是有效的int*,所以你应该这样对待它." 除非你确实知道int存储在存储器地址30 的事实,否则这是错误的.
幸运的是,你立即res用另一个 地址覆盖a.(你有两个vars命名a,两个命名res,in main和in in func.当你在那里调用它时,那些是in func的值的副本main.)一般来说,将参数的值覆盖到一个函数是"糟糕的形式",但它在技术上是合法的.就个人而言,我建议将所有函数的参数声明为const99%的时间(例如void func (const int a, const void* res))
然后,你投res了一个unsigned short.我不认为任何人仍然在16位地址空间CPU上运行(好吧,也许是你的Apple II),所以这肯定会res通过截断它来破坏它的价值.
通常,在C中,类型转换是危险的.你正在推翻编译器的类型系统,然后说:"看看这里,Compiler先生,我是程序员,我比你知道的更好.所以,你只要保持安静就能实现这一点." 从指针转换为非指针类型几乎普遍是错误的.指针类型之间的转换通常是错误的.
我建议查看本页下面的一些"相关"链接,以便总体上了解C类型指针的工作原理.有时需要阅读一些才能真正掌握这些东西如何结合在一起.
(unsigned short)res
Run Code Online (Sandbox Code Playgroud)
是一个指针上的强制转换,res是一个内存地址,通过将它转换为无符号的short,你得到的地址值是unsigned short而不是十六进制值,以确保你得到一个正确的值,你可以打印
*(unsigned short*)res
Run Code Online (Sandbox Code Playgroud)
第一个强制转换(unsigned short*)res使void*指向指针的指针unsigned short.然后,您可以通过使用取消引用它来提取内存地址res指向的值*
printf("result = %d\n", (int)res); 将 res (指针)的值打印为数字。请记住,指针是内存中的地址,因此这将打印一些看起来随机的 32 位数字。
如果您想打印存储在该地址的值,那么您需要 (int)*res - 尽管 (int) 是不必要的。
编辑:如果你想打印指针的值(即地址),那么你应该使用%p它本质上是相同的,但更好地格式化它并理解 int 和 poitner 的大小在你的平台上是否不同