-4

cの関数へのポインタとは何かを理解しようとしています。

関数へのポインターを呼び出す詳細なプロセスが必要なので、関数へのポインターをよりよく理解できました。

以下の私のコードがクラッシュせず、有線出力がある理由を誰かが説明できますか? 絞り込むために、コードをコンパイルしてコードを実行javapする方法を説明できるようなものを探していますjdkjvm

  1. void return と番号 14、15、または 16 の関係は何ですか。 (void 関数 return)
  2. 私の 2 番目のパラメーターにセキュリティ上の問題がありますか、それとも非 init val と同じですか?

test.c

#include <stdio.h>
#include <stdlib.h>


static void f(int x, int y){

    printf("x = %d \n",  x );
    printf("y = %d \n",  y );
}

typedef int (*FUNC)(int);

int main(void){

    long int addr = (long int)f;
    printf("%d \n",  (int)((FUNC)addr)(1) );

    return 0;
}

でコンパイルされた mac os での出力i686-apple-darwin11-llvm-gcc-4.2

x = 1 
y = 1479046720 
16 
4

4 に答える 4

4

The answer is undefined behavior. You're using two incompatible function pointer types and use one to call the other. (Not to mention storing the pointer in an integer, etc., etc.) Thus, your program invokes undefined behavior, and as such, anything can happen. And the values you get are most probably just random crap from the messed up stack and/or CPU registers.

于 2013-02-03T11:08:07.433 に答える
3

You are causing undefined behavior all over the place:

  • You're storing the function pointer in a integer, which isn't guaranteed to work
  • You're casting said integer to a different type of function pointer (fewer parameters) with a different return type
  • You're calling the function with fewer parameters than it expects
  • You take a return value from a function returning void

Trying to make sense of this is just unreasonable, but as a guess since you're using x86:

  • x is populated correctly in the function with the 1 you passed
  • y isn't so it gets a random value, likely some leftover on the stack
  • there's no return value and you get whatever was left in the AX register

Could somebody explain why does my code below not crash and have some wired output

Doing the wrong thing isn't guaranteed to crash your program - there are no guarantees.

于 2013-02-03T11:08:18.147 に答える
0

質問に答えるには、

以下の私のコードがクラッシュしない理由を誰かが説明できますか

すべての壊れたコードが実際にクラッシュするわけではありません。f のパラメーター (および戻り値) は、スタックにプッシュされるのではなく、レジスターに渡される可能性があります。そのため、期待値と実際の値の不一致は、スタックのミスアライメントに変換されません。スタック作業が必要なほど多くの引数を使用しようとすると、クラッシュしたり、危険な動作をしたりする可能性があります (結局のところ、一部のセキュリティ エクスプロイトでは同様の手法が使用されています)。

次に、関数ポインターの使用法を明確にするために、いくつかのコメントを付けて自由にコードを書き直しました。

#include <stdio.h>
#include <stdlib.h>

/* We want to be able to print a return value, so we make
   f return something - a long, so as to tell it from int
   - in order to be able to get something back.
*/

static long f(int x, int y){

    printf("x = %d \n",  x );
    printf("y = %d \n",  y );
    return x + y;
}

/* We want the signature of a function returning long, and taking
   two int's, since this is what f() is.
*/
typedef long (*FUNCPTR)(int, int);
typedef long (FUNC)(int, int);

int main(void)
{
    /* We want a pointer to f - it works either way */
    FUNCPTR addr   = f;
    FUNC    *addr2 = f;

    /* addr points to a function taking two ints, so we must pass it
       two ints, and format return as long decimal */

    printf("%ld\n",  addr(5, 7));

    /* addr2 is the same */

    printf("%ld\n",  addr2(5, 7));

    return 0;
}

期待される出力:

$ gcc -W -Wall -o test test.c

$ ./test
x = 5
y = 7
12
x = 5
y = 7
12
于 2013-02-03T11:31:26.610 に答える
0

最後の出力で返される値 16 は、おそらく printf によって書き込まれた文字数です。これは printf が返すものであり、この場合、関数内ではその後何も起こりません。しかし、他の人が言ったように、あなたは何が起こるかを尋ねており、誰も本当に言うことはできません.異なるコンパイラ、異なるコンパイラ設定、または異なるタイプのハードウェアでコードをコンパイルすると、結果が変わります。

コードを実行するたびに、ほとんどの場合同じ結果が得られますが、コードにいくつかの変更を加えると、予測できない結果が発生します。

于 2013-02-03T11:16:32.037 に答える