为什么char参数在参数中被提升为int?

时间:2014-11-29 23:55:01

标签: c++

我刚试过:

void p( int x, int y,int a,int b ) {
    printf( "x = 0x%p\ny = 0x%p\na = 0x%p\nb = 0x%p\n", x, y, a, b );
}

int main( ) {
    ( ( void( *)( char, char, char, char, char, char, char, char ) )&p )
        ( 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 );
}

其中预期的输出是:

x = 0x01020304
y = 0x05060708
a = 0x???????? <-- random hex value
b = 0x???????? <--

或者如果编译器反向推送参数:

x = 0x????????
y = 0x????????
a = 0x04030201
b = 0x08070605

但为什么实际输出是:

x = 0x00000001
y = 0x00000002
a = 0x00000003
b = 0x00000004

有限制吗?如果我在这里错了,请告诉我:要获得未与4个字节对齐的值,您可以在汇编中执行8B 45 01 mov eax,ebp+01h;没有问题;如果还有另一个限制,那么它是什么?

5 个答案:

答案 0 :(得分:4)

将函数指针强制转换为其他类型并使用它来调用函数会导致未定义的行为。

  

来自C11标准6.3.2.3 p8:

     

指向一种类型的函数的指针可以转换为指向另一种函数的指针   打字再回来;结果应该等于原始指针。 如果转换了   指针用于调用类型与引用类型不兼容的函数,   行为未定义。

C ++中的规则是相同的:

  

函数指针可以显式转换为不同类型的函数指针。打电话的效果   通过指向函数类型(8.3.5)的指针的函数,该函数与定义中使用的类型不同   功能未定义

答案 1 :(得分:2)

鼻腔恶魔。 §5.2.10[expr.reinterpret.cast] / p6:

  

函数指针可以显式转换为函数指针   不同类型的。通过一个函数调用函数的效果   指向与类型不同的函数类型(8.3.5)的指针   在函数定义中使用的是未定义的。

另外,使用printf 也是未定义的行为(WG14N1570§7.21.6.1/ p9):

  

如果任何参数不是相应的正确类型   转换规范,行为未定义。

如何传递函数参数取决于调用约定。常见的x64调用约定, 例如,始终在寄存器中传递前几个整数参数。

答案 2 :(得分:1)

您的程序有未定义的行为。当您给printf格式说明符%p时,相应的变量参数必须是void *类型,而程序中不是这种情况。

答案 3 :(得分:0)

这就是指定平台的C ABI的方式 - 它们通常被指定为包含这样的机制,以满足可变参数,堆栈对齐和其他此类功能。

如果您想知道为什么ABI会这样,您将不得不专门询问有关ABI的平台特定问题。

C和C ++语言都没有任何关于这个问题的说法,除了它是完全未定义的行为。它完全是ABI特有的。

答案 4 :(得分:0)

我认为你得到它,因为在任何情况下,函数参数都具有4的对齐。

我在visual studio中进行了测试,得到了相同的结果。偶#pack(1)不会影响它。

我更改你的功能以打印变量地址:

void p( int x, int y,int a,int b ) {
    printf( "x = 0x%p\ny = 0x%p\na = 0x%p\nb = 0x%p\n", &x, &y, &a, &b );
}

我得到了以下结果:

x = 0x0047F92C
y = 0x0047F930
a = 0x0047F934
b = 0x0047F938

正如你所看到的那样,正如预期的那样,指针都是4。

现在我将函数更改为chars:

void p( char x, char y,char a,char b ) {
    printf( "x = 0x%p\ny = 0x%p\na = 0x%p\nb = 0x%p\n", &x, &y, &a, &b );
} 

结果是:

x = 0x0101F750
y = 0x0101F754
a = 0x0101F758
b = 0x0101F75C

你可以看到它仍然与4对齐!

我认为它应该回答你的问题。