繁体   English   中英

明确分配C指针的地址

[英]Explicit assignment of addresses for C pointers

$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=0x7fffffffe2bc;
    y=0x7fffffffe3bc;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

在运行时产生分段错误( 没有编译时警告/错误) 编辑 :(警告:谢谢@KeithThompson)

xc:在函数“ main”中:
xc:6:警告:赋值使指针从整数开始而没有强制转换

[ 8626.812415] x[3198]: segfault at 7fffffffe2bc ip 000000000040054c sp 00007fff66a1dd70 error 6 in x[400000+1000]

但是当我将x,y分配给q,w时

$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=&q;
    y=&w;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

并获得输出,我得到0 我什至从gdb检查了q和w的地址,q的值为0x7fffffffe2bc

为什么不能强制指针指向特定位置并为其提供要存储的值?

编辑地址0x7fffffffe2bc尚未分配 这是来自gdb的q的地址

Breakpoint 1, main () at x.c:10
10      *x=3;*y=4;
(gdb) p q
$1 = 0
(gdb) p &q
$2 = (int *) 0x7fffffffe2bc
(gdb) 

我了解这种编写代码的方法如果正确的话是不好的。 我只是写这个来看看地址的明确分配是否有效。 我永远不会浪费时间明确分配地址。 这样做实际上听起来很迟钝:)

$ gdb -q ./a.out 
Reading symbols from /home/eknath/needed2/a.out...done.
(gdb) r
Starting program: /home/eknath/needed2/a.out 
0

Program exited normally.
(gdb) q

因为您还没有为数据分配内存,所以只分配了指针。 您充其量只是在浪费内存,而在最坏的情况下会碰到未分配的内存段。 无法知道要使用哪些地址-每次运行应用程序时,它们可能会有所不同。

如果要动态分配变量(即,在您自己的控制下),请使用malloc:

int *x = (int*) malloc( sizeof(int) );
*x = 2;

// when done, free the memory
free( (void*) x );

这段代码:

int *x,q;
...
x=0x7fffffffe2bc;

是无效的。 这是违反约束的情况,这意味着需要任何符合条件的编译器才能发出诊断消息。 您说“在编译该程序时没有警告/错误”,这意味着您正在使用旧的编译器,或者使用了错误的新编译器。

xint*类型的; 0x7fffffffe2bc是某种整数类型。 没有从整数类型到int*隐式转换(特殊情况为0 ,即空指针常量)。

可以合法地写类似:

x = (int*)0x7fffffffe2bc;

但这是一个非常糟糕的主意。 它使您的程序不可移植。 它可能会(也可能不会)在您的特定系统上运行。

无论您要完成什么,这都不是做到的方式。 您无法知道0x7fffffffe2bc (转换为int* )是有效地址-即使它是有效地址,也无法在稍微不同的环境中运行程序。

编辑

我尝试通过打印qw的地址,然后将这些地址硬连接到代码中,在系统(地址完全不同)上重现您的程序。 每次执行程序时实际地址都会更改,即使我不更改或重新编译程序本身也是如此。 我认为某些系统会故意将其作为安全功能。 (我看到dmckee的答案已经提到了这一点。)

打印变量的地址,或使用gdb查看它,只会告诉您在程序的特定执行过程中该变量的地址。 程序完成运行后,即使您重新运行同一程序而不进行更改,该信息也无济于事

如果您想要q的地址,则获取它的方法是&q

void myFunction(char *addr)
{
#ifdef UMEM_DEBUG
    if (addr == (char *) 0xdeadbeefdeadbeef)
    {
        return;
    }
#endif
...
}

这行得通,并且是您何时要执行此操作的一个很好的示例。 只需根据addr的类型正确地进行类型转换

这种事情完全取决于实现/环境(并且通常是未定义的行为),但是它确实在嵌入式系统和其他环境中占有一席之地,在这些环境中,您与绝对一切之间都没有OS层。

许多功能齐全的OS会随机分配堆栈和/或堆的起始地址,以使攻击更加困难,如果是这种情况,您将无法执行任何可靠的技巧。

问题不在代码中,也不在编译器/链接器中。 这两个程序都可以正常工作。 只是有一个很大的BUT :仅仅是因为您可以指向内存,但这并不意味着MMU(例如操作系统)将允许您访问它

让我澄清一下:通常,您只能访问“拥有”的内存(堆栈/堆)。 在两种情况下,对x和y的分配都是有效的。 棘手的部分是当您访问内存(读或写)时。 在第一种情况下,您为指针分配了一些随机值,因此该位置不会在程序的范围内(==不能触摸它)。 虽然,在第二种情况下,您正在访问您可能拥有的变量的存储位置。

为什么会呢? 因为对变量q和w进行了优化,因为它们从未使用过,所以它们将被优化。

切记:除非您喜欢问题,否则永远不要引用未初始化的变量

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM