【问题标题】:Why does a string stored in an integer gets printed out?为什么存储在整数中的字符串会被打印出来?
【发布时间】:2015-12-08 17:53:22
【问题描述】:
int k= "hello";
printf("%s", k);

为什么即使 k 的数据类型是整数,这个 hello 也会打印出来?

【问题讨论】:

  • 实际上这会发出警告initialization makes a integer out of pointer.. 这段代码是如何为您编译的??
  • @ThunderWiring 代码编译不会出错(假设没有-Werror标志),只有警告。
  • 我不知道怎么做。它在 CodeBlocks 和 Visual Studio 2013 上编译。
  • 对,我正在使用 -Werror
  • 代码很可能不会在 64 位平台上运行,因为当"hello" 的地址存储在k 中时,该地址的高 32 位会丢失,因为k 只有 32 位宽。

标签: c string integer


【解决方案1】:

您的代码调用Undefined Behavior

int k= "hello";

您正在尝试使用字符串文字(char*)初始化 int。这毫无意义,会调用UB

printf("%s", k);

您正在尝试使用%s 打印int,它需要char*。这也没有任何意义,会调用UB

【讨论】:

  • 我知道这没有意义,但为什么它会起作用呢?
  • 什么有效? UB 意味着任何事情都可能是结果。别再做这种傻事了。你会得到意想不到的结果。
  • 这就是为什么你应该在编译时使用-Werror标志~
  • 对未定义行为的一个合法回应是按照程序员的意图去做。但是,你不能指望它。上面的代码不适用于 ILP32 模型,或者像 68k 这样具有单独地址和整数寄存器的 CPU。
【解决方案2】:

这里,hello 是一个字符串文字,因此它存储在可执行文件的文本部分(沿着代码),当您将其分配给整数时,实际上指向文字的指针将分配给整数.由于两者通常大小相同(4字节),不会出现堆栈溢出等问题。

printf 可以正常工作,因为它将转到存储在变量中的地址(此处为 k)并打印字符串,直到找到字符串结尾 \0

【讨论】:

  • "由于两者大小相同" 这通常不会在 64 位实现中出现。
【解决方案3】:

注意 - 所做的事情是错误的,并且几乎提供了不受欢迎的 结果(在某些情况下,忽略警告是一种犯罪行为,这是其中之一 那些情况)。

关于为什么它为你打印字符串,这是我的解释

在给定格式说明符 %s 的情况下,给定参数被识别/解释为字符串的基地址 (char *)。现在 char * 和 int 在逻辑上相等(忽略 C 施加的符号和其他属性)

所以在一个非常原始的水平

int a = "String" ;

大概是这个样子

     a  contains Base address of String ( this is some read only location )
    +-----+-----+-----+-----+
    |  0x123456             |
    +-----+-----+-----+-----+

    And String may be defines as below with 'S' at location 0x123456

0x123456  
    +-----+-----+-----+-----+-----+-----+-----+
    |  S  | t   |  r  |  i  |  n  |  g  |  \0 |
    +-----+-----+-----+-----+-----+-----+-----+

%s 格式说明符的参数将被视为 (char*)

现在,如果 %s 作为格式说明符,程序应该扫描从给定地址开始的每个内存字节,然后类型转换为 char,然后打印(当然取决于可打印的值与否,结果可能很漂亮 可怕)

在我们的例子中,虽然将 a 的给定值取消引用到 char * 不会产生任何问题,因此不会出现错误,但是这不一定总是如此。有不同的原因。

【讨论】:

    【解决方案4】:

    您的代码忽略了 C 的类型系统,因此在尝试理解您的代码时需要忽略类型系统。

    我希望你的机器上有 sizeof(int)==sizeof(char*)。 const char* 文字被分配给 k。这是有效的,因为您机器上的每个字节都有一个整数地址。类型系统的“底层”,指针就是这个整数。

    printf 之所以有效,是因为它将 k 解释为一个 const char* 到一个以 null 结尾的数组,这是您分配给 k 的内容。

    正如其他人所指出的,您的代码不能保证可以正常工作,因此它不应该出现在您计划发布的任何软件中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 2011-08-21
      相关资源
      最近更新 更多