由直接C生成的特殊指令序列;如果;缺乏条件

由直接C生成的特殊指令序列;如果;缺乏条件,c,C,我试图在gcc(Ubuntu/Linaro4.6.3-1ubuntu5)4.6.3下为x86-64调试一些简单的C代码。代码是用CFLAGS+=-std=c99-g-Wall-O0构建的 #include <errno.h> #include <stdio.h> #include <string.h> #pragma pack(1) int main (int argc, char **argv) { FILE *f = fopen (

我试图在gcc(Ubuntu/Linaro4.6.3-1ubuntu5)4.6.3下为x86-64调试一些简单的C代码。代码是用
CFLAGS+=-std=c99-g-Wall-O0构建的

#include <errno.h>
#include <stdio.h>
#include <string.h>
#pragma pack(1)

int main (int argc, char **argv)
{
        FILE    *f = fopen ("the_file", "r"); /* error checking removed for clarity */

        struct {
                short   len;
                short   itm [4];
                char    nul;
        } f00f;

        int n = fread (&f00f, 1, sizeof f00f, f);

        if (f00f.nul   ||
            f00f.len != 0x900       ||      
            f00f.itm [0] != 0xf00f  ||      
            f00f.itm [1] != 0xf00f  ||
            f00f.itm [2] != 0xf00f  ||
            f00f.itm [3] != 0xf00f)
        {
                fprintf (stderr, "bitfile_hdr F00F data err:\n"
                    "\tNUL:  0x%x\n"
                    "\tlen:  0x%hx should be 0x900\n"
                    "\tf00f:  0x%hx\n"
                    "\tf00f:  0x%hx\n"
                    "\tf00f:  0x%hx\n"
                    "\tf00f:  0x%hx\n"
                    , f00f.nul, f00f.len,
                    f00f.itm[0], f00f.itm[1], f00f.itm[2], f00f.itm[3]
                    );
                return 1;
         }
         return  0;
}
gdb
下运行它并检查结构也会显示正确的数据

(gdb) p /x f00f
$1 = {len = 0x900, itm = {0xf00f, 0xf00f, 0xf00f, 0xf00f}, nul = 0x0}
由于这没有意义,我检查了gdb内部的指令,以揭示编码病理学。与不起作用的
if
对应的说明如下:

   0x0000000000400736 <+210>:   movzwl -0x38(%rbp),%eax
   0x000000000040073a <+214>:   movswl %ax,%r8d
   0x000000000040073e <+218>:   movzwl -0x3a(%rbp),%eax
   0x0000000000400742 <+222>:   movswl %ax,%edi
   0x0000000000400745 <+225>:   movzwl -0x3c(%rbp),%eax
   0x0000000000400749 <+229>:   movswl %ax,%r9d
   0x000000000040074d <+233>:   movzwl -0x3e(%rbp),%eax
   0x0000000000400751 <+237>:   movswl %ax,%r10d
   0x0000000000400755 <+241>:   movzwl -0x40(%rbp),%eax
   0x0000000000400759 <+245>:   movswl %ax,%ecx
   0x000000000040075c <+248>:   movzbl -0x36(%rbp),%eax
   0x0000000000400760 <+252>:   movsbl %al,%edx
   0x0000000000400763 <+255>:   mov    $0x4008d8,%esi
   0x0000000000400768 <+260>:   mov    0x2008d1(%rip),%rax  # 0x601040 <stderr@@GLIBC_2.2.5>
   0x000000000040076f <+267>:   mov    %r8d,0x8(%rsp)
   0x0000000000400774 <+272>:   mov    %edi,(%rsp)
   0x0000000000400777 <+275>:   mov    %r10d,%r8d
   0x000000000040077a <+278>:   mov    %rax,%rdi
   0x000000000040077d <+281>:   mov    $0x0,%eax
   0x0000000000400782 <+286>:   callq  0x400550 <fprintf@plt>
   0x0000000000400787 <+291>:   mov    $0x6,%eax
   0x000000000040078c <+296>:   add    $0x50,%rsp
   0x0000000000400790 <+300>:   pop    %rbx
   0x0000000000400791 <+301>:   pop    %r12
   0x0000000000400793 <+303>:   pop    %rbp
   0x0000000000400794 <+304>:   retq   
0x0000000000400736:movzwl-0x38(%rbp),%eax
0x000000000040073a:movswl%ax,%r8d
0x000000000040073e:movzwl-0x3a(%rbp),%eax
0x0000000000400742:movswl%ax,%edi
0x0000000000400745:movzwl-0x3c(%rbp),%eax
0x0000000000400749:movswl%ax,%r9d
0x000000000040074d:movzwl-0x3e(%rbp),%eax
0x0000000000400751:movswl%ax,%r10d
0x0000000000400755:movzwl-0x40(%rbp),%eax
0x0000000000400759:movswl%ax,%ecx
0x000000000040075c:movzbl-0x36(%rbp),%eax
0x0000000000400760:movsbl%al,%edx
0x0000000000400763:mov$0x4008d8,%esi
0x0000000000400768:mov 0x2008d1(%rip),%rax#0x601040
0x000000000040076f:mov%r8d,0x8(%rsp)
0x0000000000400774:mov%edi,(%rsp)
0x0000000000400777:mov%r10d,%r8d
0x000000000040077a:mov%rax,%rdi
0x000000000040077d:mov$0x0,%eax
0x0000000000400782:callq 0x400550
0x0000000000400787:mov$0x6,%eax
0x000000000040078c:添加$0x50,%rsp
0x0000000000400790:弹出%rbx
0x0000000000400791:弹出%r12
0x0000000000400793:弹出%rbp
0x0000000000400794:retq
很难看出这是如何实现有条件的


有人知道这(mis)为什么会这样吗?

可能在您的平台上,
short
是16位宽。因此,任何
short
都不能等于
0xf00f
和条件
f00f.itm[0]!=0xf00f
始终为真。编译器进行了相应的优化


struct f00f
的定义中,您可能指的是
unsigned short
,但这当然只是修复它的一种方法。您也可以将
f00f.itm[0]
(short)0xf00f
进行比较,但如果您的意思是
f00f.itm[i]
0xf00f
进行比较,您肯定应该在定义中使用
无符号short
将值-4081指定给val

你会被整数提升规则击中

 f00f.itm [0] != 0xf00f
f00f.itm[0]
中的短字符转换为int,即-4081。0xf00f作为int是61455,这两个值不相等。由于在打印值时(通过使用
%hx
),该值会转换为无符号的短字符,因此在输出中看不到该问题

在结构中使用无符号值,因为您似乎将这些值视为无符号:

struct {
           unsigned short   len;
           unsigned short   itm [4];
           char    nul;
    } f00f;
此示例程序可能会让您更好地了解正在发生的事情:

#include <stdio.h>

int main(int argc,char *arga[])
{
    short x = 0xf00f;
    int y  =  0xf00f;

    printf("x = 0x%hx y = 0x%x\n", x, y);
    printf("x = %d y = %d\n", x, y);
    printf("x==y: %d\n", x == y);

    return 0;
}
#包括
int main(int argc,char*arga[])
{
短x=0xf00f;
int y=0xf00f;
printf(“x=0x%hx y=0x%x\n”,x,y);
printf(“x=%d y=%d\n”,x,y);
printf(“x==y:%d\n”,x==y);
返回0;
}

与您的问题无关,但不会
fread(&f00f,1,sizeof f00f,f)使fread(&f00f,sizeof f00f,1,f)更有意义?根据我的文档,这将确保您不会阅读半个结构。该程序集是否紧跟在
fread
调用之后?@PascalCuoq:我认为
fread
的文档没有那么有用。我通常希望验证字节数,而不是项目数。这就是为什么我总是“把它转过来”,以便能够报告一个简短的阅读有多短。在一个无关的注释上,请清理您的代码conventions@aschepler:是的,逻辑上是这样。在未桥接的代码中,检查
fread
读取的字节是否足以填充结构。我把它取出来是因为a)它总是有效的,b)为了简化问题。Short是16位,但0xf00f也是如此。@wallyk
0xf00f
适合16位无符号整数类型,但它不适合16位有符号整数类型。在gcc中,
-Wextra
将警告此类比较:
警告:由于数据类型[-Wtype limits]的范围有限,比较始终为真。
是的。这就是问题所在。谢谢是的,这就是问题所在。我只是验证了一下,但既然帕斯卡先回答了,他就得到了荣誉。
#include <stdio.h>

int main(int argc,char *arga[])
{
    short x = 0xf00f;
    int y  =  0xf00f;

    printf("x = 0x%hx y = 0x%x\n", x, y);
    printf("x = %d y = %d\n", x, y);
    printf("x==y: %d\n", x == y);

    return 0;
}