如何在C语言中确定处理器的字长?

3
我是一名有帮助的助手,以下是您需要翻译的内容:

在面试中,我遇到了一个问题:“如何在C语言中不使用sizeof()函数确定处理器字长?”我相信我的回答是错误的。

我的代码如下:

int main(){
    int num = -1;
    int count = 0;    

    unsigned int num_copy = (unsigned int)num;
    while(num_copy >>= 1){
        count++;
    }

    printf("System size of int:%d", (count  + 1)/ 8);

    return 0;
}

输出答案仅由编译器选项决定。那么,我如何获得正确的答案(系统字长)?

如果我将这个问题的一部分从“处理器字长”改为“操作系统字长”,会发生什么?


7
sizeof 有什么问题? - jxh
我尝试根据您的评论澄清您的问题。如果我没有捕捉到您的意图,请随时改进或回滚编辑。 - Angew is no longer proud of SO
如果您的意思是为64位CPU获取64位,为32位CPU获取32位,则通常使用long。请注意,在64位CPU中,int为32位,并且在指针复制和存储时,使用long或(更常见的是)unsigned long以匹配CPU字长。 - holgac
@JY___ 是的,这是由C标准保证的。请查看我在Jonathon回复中的评论。 - holgac
2
@holgac 一个架构是32位还是64位通常由指针的大小确定。我认为即使有奇怪的数据模型也有例外。但是intptr_t应该比long更好。例如,64位Windows上的数据模型具有32位长整型。 - typ1232
显示剩余6条评论
4个回答

3

@holgac提到的那样,long数据类型的大小始终与机器的本机字长相同:

“一个字是一台计算机可以一次处理的数据量。”“处理器通用寄存器(GPR)的大小等于其字长。” “此外,C类型long的大小等于字长,而int类型的大小有时小于字长”

-- 《Linux内核开发》第17章(第3版,第381页)

然而,正如Thomas Matthews所指出的, 这可能不适用于字长较小的机器。

要确定编译器中long的大小,只需使用sizeof(long)

int main(void)
{
    printf("long is %d bits on this system\n", (int)sizeof(long)*CHAR_BIT);
    return 0;
}

另请参阅:


1
@Angew 同意,但我理解“system int size”指的是您编译器上int类型的大小。 - Jonathon Reinhart
long 的长度总是与 CPU 字长相同。 - holgac
1
《Linux内核开发》第17章(第3版,第381页)指出:“一个字是机器一次可以处理的数据量。”“处理器通用寄存器(GPR)的大小等于其字长。”“此外,C类型long的大小等于字长,而int类型的大小有时小于字长。” - holgac
@JonathonReinhart 没必要了,谢谢你的提议 :) - holgac
1
Downvote: long类型基于一定范围的值,而不是处理器的字长。在8位和16位处理器上,为了满足范围规定,long类型将占用多个处理器字长。因此,根据您的说法,在8位处理器上,long类型的范围将为8位,比int类型的范围更小。 - Thomas Matthews
显示剩余10条评论

2
我觉得我的强迫症在这里有点发作了,以下是结果:
#include <stdio.h>
#include <limits.h>

#define SIZEOF_CHAR sizeof(char)
#define SIZEOF_INT sizeof(int)
#define SIZEOF_LONG sizeof(long)
#define SIZEOF_POINTER sizeof(void *)

#define NIBBLE_BIT 4
#ifndef CHAR_BIT
#define CHAR_BIT 8    // should have been defined in <limits.h>
#endif
#define INT_BIT (SIZEOF_INT * CHAR_BIT)
#define LONG_BIT (SIZEOF_LONG * CHAR_BIT)
#define POINTER_BIT (SIZEOF_POINTER * CHAR_BIT)

int main(void)
{
  char hexchar[SIZEOF_CHAR * 2 + 1],
       hexint[SIZEOF_INT * 2 + 1],
       hexlong[SIZEOF_LONG * 2 + 1],
       hexpointer[SIZEOF_POINTER * 2 + 1];
  int strlen_hexchar, strlen_hexint, strlen_hexlong, strlen_hexpointer;

  strlen_hexchar = sprintf(hexchar, "%x", (unsigned char)-1);
  strlen_hexint = sprintf(hexint, "%x", (unsigned int)-1);
  strlen_hexlong = sprintf(hexlong, "%x", (unsigned long)-1l);
  strlen_hexpointer = sprintf(hexpointer, "%p", (void*)-1l);

  printf("#define SIZEOF_CHAR sizeof(char)                // %2d\n", SIZEOF_CHAR);
  printf("#define SIZEOF_INT sizeof(int)                  // %2d\n", SIZEOF_INT);
  printf("#define SIZEOF_LONG sizeof(long)                  // %2d\n", SIZEOF_LONG);
  printf("#define SIZEOF_POINTER sizeof(void *)           // %2d\n", SIZEOF_POINTER);

  printf("\n");

  printf("#define NIBBLE_BIT %-2d\n", NIBBLE_BIT);
  printf("#ifndef CHAR_BIT\n");
  printf("#define CHAR_BIT %-2d   // should have been defined in <limits.h>\n", CHAR_BIT);
  printf("#endif\n");
  printf("#define INT_BIT (SIZEOF_INT * CHAR_BIT)         // %2d\n", INT_BIT);
  printf("#define INT_LONG (INT_LONG * CHAR_BIT)         // %2d\n", LONG_BIT);
  printf("#define POINTER_BIT (SIZEOF_POINTER * CHAR_BIT) // %2d\n", POINTER_BIT);

  printf("\n");

  printf("\nTest setup...\n");
  printf("\n");

  printf("char hexchar[CHAR_BIT * SIZEOF_CHAR + 1],\n");
  printf("    hexint[CHAR_BIT * SIZEOF_INT + 1],\n");
  printf("    hexlong[CHAR_BIT * SIZEOF_LONG + 1],\n");
  printf("    hexpointer[CHAR_BIT * SIZEOF_POINTER + 1];\n");
  printf("int strlen_hexchar, strlen_hexint, strlen_hexlong, strlen_hexpointer;\n");
  printf("\n");
  printf("strlen_hexchar = sprintf(hexchar, \"%%x\", (unsigned char)-1);\n//    returned %d, hexchar populated with \"%s\"\n",
      strlen_hexchar, hexchar);
  printf("strlen_hexint = sprintf(hexint, \"%%x\", (unsigned int)-1);\n//    returned %d, hexint populated with \"%s\"\n",
      strlen_hexint, hexint);
  printf("strlen_hexlong = sprintf(hexlong, \"%%x\", (unsigned long)-1);\n//    returned %d, hexlong populated with \"%s\"\n",
      strlen_hexlong, hexlong);
  printf("strlen_hexpointer = sprintf(hexpointer, \"%%x\", (void*)-1l);\n//    returned %d, hexpointer populated with \"%s\"\n",
      strlen_hexpointer, hexpointer);

  printf("\n\nTest results...\n");
  printf("\n");

  if (SIZEOF_CHAR * 2 == strlen_hexchar) {
    printf("testing (SIZEOF_CHAR * 2 == strlen_hexchar) [pass]\n");
  } else {
    printf("testing (SIZEOF_CHAR * 2 == strlen_hexchar) [fail]\n");
    printf("  (%d != $d)\n", SIZEOF_CHAR * 2, strlen_hexchar);
  }

  if (SIZEOF_INT * 2 == strlen_hexint) {
    printf("testing (SIZEOF_INT * 2 == strlen_hexint) [pass]\n");
  } else {
    printf("testing (SIZEOF_INT * 2 == strlen_hexint) [fail]\n");
    printf("  (%d != $d)\n", SIZEOF_INT * 2, strlen_hexint);
  }

  if (SIZEOF_LONG * 2 == strlen_hexlong) {
    printf("testing (SIZEOF_LONG * 2 == strlen_hexlong) [pass]\n");
  } else {
    printf("testing (SIZEOF_LONG * 2 == strlen_hexlong) [fail]\n");
    printf("  (%d != $d)\n", SIZEOF_LONG * 2, strlen_hexlong);
  }

  if (SIZEOF_POINTER * 2 == strlen_hexpointer) {
    printf("testing (SIZEOF_POINTER * 2 == strlen_hexpointer) [pass]\n");
  } else {
    printf("testing (SIZEOF_POINTER * 2 == strlen_hexpointer) [fail]\n");
    printf("  (%d != $d)\n", SIZEOF_POINTER * 2, strlen_hexpointer);
  }

  printf("\n");

  if (CHAR_BIT == strlen_hexchar * NIBBLE_BIT) {
    printf("testing (CHAR_BIT == strlen_hexchar * NIBBLE_BIT) [pass]\n");
  } else {
    printf("testing (CHAR_BIT == strlen_hexchar * NIBBLE_BIT) [fail]\n");
    printf("  (%d != $d)\n", CHAR_BIT, strlen_hexchar * NIBBLE_BIT);
  }

  if (INT_BIT == strlen_hexint * NIBBLE_BIT) {
    printf("testing (INT_BIT == strlen_hexint * NIBBLE_BIT) [pass]\n");
  } else {
    printf("testing (INT_BIT == strlen_hexint * NIBBLE_BIT) [fail]\n");
    printf("  (%d != $d)\n", INT_BIT, strlen_hexint * NIBBLE_BIT);
  }

  if (LONG_BIT == strlen_hexlong * NIBBLE_BIT) {
    printf("testing (LONG_BIT == strlen_hexlong * NIBBLE_BIT) [pass]\n");
  } else {
    printf("testing (LONG_BIT == strlen_hexlong * NIBBLE_BIT) [fail]\n");
    printf("  (%d != $d)\n", LONG_BIT, strlen_hexlong * NIBBLE_BIT);
  }

  if (POINTER_BIT == strlen_hexpointer * 4) {
    printf("testing (POINTER_BIT == strlen_hexpointer * NIBBLE_BIT) [pass]\n");
  } else {
    printf("testing (POINTER_BIT == strlen_hexpointer * NIBBLE_BIT) [fail]\n");
    printf("  (%d != $d)\n", POINTER_BIT, strlen_hexpointer * NIBBLE_BIT);
  }

  printf("\n");

  if ((int)(SIZEOF_POINTER * CHAR_BIT) == strlen_hexpointer * NIBBLE_BIT) {
    printf("testing ((int)(SIZEOF_POINTER * CHAR_BIT) == strlen_hexpointer * NIBBLE_BIT) [pass]\n");
  } else {
    printf("testing ((int)(SIZEOF_POINTER * CHAR_BIT) == strlen_hexpointer * NIBBLE_BIT) [fail]\n");
    printf("  (%d != %d)\n", (int)(SIZEOF_POINTER * CHAR_BIT), strlen_hexpointer * NIBBLE_BIT);
  }

  printf("\nConclusion: this machine word is %d bytes and %d bits\n", SIZEOF_POINTER * 8 / CHAR_BIT, strlen_hexpointer * NIBBLE_BIT);
  if ((int)(SIZEOF_POINTER * CHAR_BIT) != strlen_hexpointer * NIBBLE_BIT) {
    printf(" * however this conclusion did not pass the (int)(SIZEOF_POINTER * 8 / CHAR_BIT) == strlen_hexpointer * NIBBLE_BIT) test\n");
  }

  return 0;
}

这段代码的输出在我的机器上如下所示:
$ sizeofword.exe # from mingw32 shell on windows7
#define SIZEOF_CHAR sizeof(char)                //  1
#define SIZEOF_INT sizeof(int)                  //  4
#define SIZEOF_LONG sizeof(long)                  //  4
#define SIZEOF_POINTER sizeof(void *)           //  4

#define NIBBLE_BIT 4
#ifndef CHAR_BIT
#define CHAR_BIT 8    // should have been defined in <limits.h>
#endif
#define INT_BIT (SIZEOF_INT * CHAR_BIT)         // 32
#define INT_LONG (INT_LONG * CHAR_BIT)         // 32
#define POINTER_BIT (SIZEOF_POINTER * CHAR_BIT) // 32


Test setup...

char hexchar[CHAR_BIT * SIZEOF_CHAR + 1],
    hexint[CHAR_BIT * SIZEOF_INT + 1],
    hexlong[CHAR_BIT * SIZEOF_LONG + 1],
    hexpointer[CHAR_BIT * SIZEOF_POINTER + 1];
int strlen_hexchar, strlen_hexint, strlen_hexlong, strlen_hexpointer;

strlen_hexchar = sprintf(hexchar, "%x", (unsigned char)-1);
//    returned 2, hexchar populated with "ff"
strlen_hexint = sprintf(hexint, "%x", (unsigned int)-1);
//    returned 8, hexint populated with "ffffffff"
strlen_hexlong = sprintf(hexlong, "%x", (unsigned long)-1);
//    returned 8, hexlong populated with "ffffffff"
strlen_hexpointer = sprintf(hexpointer, "%x", (void*)-1l);
//    returned 8, hexpointer populated with "FFFFFFFF"


Test results...

testing (SIZEOF_CHAR * 2 == strlen_hexchar) [pass]
testing (SIZEOF_INT * 2 == strlen_hexint) [pass]
testing (SIZEOF_LONG * 2 == strlen_hexlong) [pass]
testing (SIZEOF_POINTER * 2 == strlen_hexpointer) [pass]

testing (CHAR_BIT == strlen_hexchar * NIBBLE_BIT) [pass]
testing (INT_BIT == strlen_hexint * NIBBLE_BIT) [pass]
testing (LONG_BIT == strlen_hexlong * NIBBLE_BIT) [pass]
testing (POINTER_BIT == strlen_hexpointer * NIBBLE_BIT) [pass]

testing ((int)(SIZEOF_POINTER * CHAR_BIT) == strlen_hexpointer * NIBBLE_BIT) [pass]

Conclusion: this machine word is 4 bytes and 32 bits

该程序在32位的Windows 7上运行。 - Erich Horn
我添加了long并将其放在gist中(https://gist.github.com/f03f1071bce240654ec4.git) - Erich Horn
我想我应该补充一下,以便准确无误,即sizeof(void*) * CHAR_BIT应该是机器字长的位数,但实际上可能是sizeof(void*) * 8。不太确定,但我认为实际上应该是相同的。在C中,无论是UTC-8还是16或其他什么,char都是8位。但是又总会有例外。你可以信赖的一件事是,一个nibble始终为4位。因此,使用sprintf应该可以验证这一点。 - Erich Horn

1

是否允许使用sizeof

此外,稍微改进一下实现(无需复制,循环次数更少,不需要除法):

int main(){
    int num = 1;
    int count = 0;    

    while(num <<= 8){
        count++;
    }

    printf("System size of int:%d", count+1);

    return 0;
}

你说得对。sizeof()也会获取编译器的int大小。我在想是否有类似于宏#program的方式可以完成这个任务。 - Tommy

0
作为一个面试问题,在纯C中唯一正确的方法是使用条件编译。条件编译允许在软件运行的各个平台上定义不同的字长,或者以某种方式标识出正确的大小可以从数据库中获取。由于公司知道产品将在哪些平台上运行,或者愿意支持哪些平台,因此可以在编译或运行时选择平台,并选择正确的字长。
其他任何获取字长的方法都要么是特定于平台/系统的代码,要么是一种启发式方法。一种可能的启发式方法是使用指针的大小来表示机器字长。
word_size = sizeof(void *);

鉴于这是一种启发式方法,有一些平台它可能会失效


这个能在函数指针不仅仅是指针的架构上工作吗?我记得Itanium在这方面很奇怪,有一个函数“描述符”之类的东西。 - Jonathon Reinhart
@JonathonReinhart: 我将其更改为常规指针。想法是选择机器愿意使用整个寄存器来保存的内容。这可能适用于16位系统,其中sizeof(long)必须失败。 - jxh
有些64位架构使用32位指针。请参见http://en.wikipedia.org/wiki/Memory_address#Word_size_versus_address_size。 - holgac
@holgac:谢谢,已在答案中注意到。 - jxh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接