关于 C 参数提升的问题

发布于 2024-11-07 12:12:56 字数 2021 浏览 0 评论 0原文

好吧,实际上我已经研究了如何使用循环来使我的代码更高效,以便我可以使用应该重复的特定代码块,而无需一遍又一遍地输入它,并且在尝试使用我学到的东西之后距离编程还远了,我觉得是时候进入下一章学习如何使用控制语句来指导程序做出决定了。

但问题是,在我继续之前,我仍然有一些问题需要任何专家对之前的内容的帮助。实际上这是关于数据类型的。


A.字符类型

  1. 我从《C Primer Plus 5th ed》一书中摘录了以下内容:

有点奇怪的是,C 对待字符 常量为 int 类型,而不是 字符。例如,在 ASCII 系统上 具有 32 位 int 和 8 位 char ,代码:

字符等级 = 'B';

代表'B'为数值 66 以 32 位为单位存储,grade 最终得到 66 个存储的 ub ab 8 位 单元。这种性格特征 常量使得可以定义 字符常量,例如 'FATE', 具有四个独立的 8 位 ASCII 代码 以32位为单位存储。然而 , 尝试分配这样一个字符 常量为 char 变量结果 仅使用最后 8 位, 因此变量的值是'E'

  1. 所以读完这篇文章后我做的下一件事当然是按照它提到的内容进行操作,即我尝试将单词 FATE 存储在具有 chargrade 的变量上,并且尝试编译并查看使用 printf() 存储的内容,但我得到的是 ',而不是打印出字符 'E' F'.

  2. 这是否意味着书中存在一些错误?还是我误解了什么?

  3. 从上面的句子中,有一行说C将字符常量视为int类型。因此,为了尝试一下,我为 char 类型分配了一个大于 255(例如 356)的数字。

  4. 由于 356 在 32 位 int 的范围内(我运行的是 Windows 7),因此我希望它会打印出 356 当我使用 %d 说明符时。

  5. 但它没有打印 356,而是给我 100,这是最后 8 位值。

  6. 为什么会发生这种情况?我认为char == int == 32位? (尽管它之前确实提到 char 只是一个字节)。


B. Int 和 Floating 类型

  1. 我明白,当以 short 类型存储在变量中的数字传递给可变参数函数或任何隐式原型函数时,它将自动提升为 int 类型。

  2. 浮点类型也会出现这种情况,当传递float类型的浮点数时,它会被转换为double类型,这就是为什么有float 类型没有说明符,但只有 %f 表示 double%Lf 表示 long double

  3. 但是为什么有一个 short 类型的说明符,尽管它也被提升,但没有 float 类型?为什么他们不直接为 float 类型提供一个说明符,并带有诸如 %hf 之类的修饰符?这背后有什么逻辑或技术吗?

Alright actually I've study about how to use looping to make my code more efficient so that I could use a particular block of code that should be repeated without typing it over and over again, and after attempted to use what I've learn so far to program something, I feel it's time for me to proceed to the next chapter to learn on how to use control statement to learn how to instructs the program to make decision.

But the thing is that, before I advance myself to it, I still have a few question that need any expert's help on previous stuff. Actually it's about datatype.


A. Character Type

  1. I extract the following from the book C primer Plus 5th ed:

Somewhat oddly , C treats character
constans as type int rather than
char. For example, on an ASCII system
with a 32-bit int and an 8-bit char
, the code:

char grade = 'B';

represents 'B' as the numerical value
66 stored in a 32-bit unit, grade
winds up with 66 stored ub ab 8-bit
unit. This characteristic of character
constants makes it possible to define
a character constant such as 'FATE',
with four separate 8-bit ASCII codes
stored in a 32-bit unit. However ,
attempting to assign such a character
constant to a char variable results
in only the last 8 bits being used,
so the variable gets the value 'E'.

  1. So the next thing I did after reading this was of course, follow what it mentions, that is I try store the word FATE on a variable with char grade and try to compile and see what it'll be stored using printf(), but instead of getting the character 'E' printed out, what I get is 'F'.

  2. Does this mean there's some mistake in the book? OR is there something I misunderstood?

  3. From the above sentences, there's a line says C treats character constants as type int. So to try it out, I assign a number bigger than 255, (e.x. 356) to the char type.

  4. Since 356 is within the range of 32-bit int (I'm running Windows 7), therefore I expect it would print out 356 when I use the %d specifier.

  5. But instead of printing 356, it gives me 100, which is the last 8-bits value.

  6. Why does this happen? I thought char == int == 32-bits? (Although it does mention before char is only a byte).


B. Int and Floating Type

  1. I understand when a number stores in variable in short type is pass to variadic function or any implicit prototype function, it'll be automatically promoted to int type.

  2. This also happen to floating point type, when a floating-point number with float type is passed, it'll be converted to double type, that is why there's no specifier for the float type but instead there's only %f for double and %Lf for long double.

  3. But why there's a specifier for short type although it is also promoted but not float type? Why don't they just give a specifier for float type with a modifier like %hf or something? Is there anything logical or technical behind this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淡淡绿茶香 2024-11-14 12:12:56

一个问题中有很多问题......以下是几个问题的答案:

字符常量的这一特性使得定义诸如“FATE”之类的字符常量成为可能,其中四个单独的 8 位 ASCII 代码存储在 32 位单元中。但是,尝试将这样的字符常量分配给 char变量导致仅使用最后 8 位,因此该变量的值为“E”。

这实际上是实现定义的行为。所以,是的,书中有一个错误。许多关于 C 的书籍在编写时都假设世界上唯一的 C 编译器是作者在测试示例时使用的编译器。

作者使用的编译器将“FATE”中的字符视为整数的字节,其中“F”是最高有效字节,“E”是最低有效字节。您的编译器将文字中的字符视为整数字节,其中“F”是最低有效字节,“E”是最高有效字节。例如,第一种方法是 MSVC 如何处理值,而 MinGW(面向 Windows 的 GCC 编译器)则以第二种方式处理文字。

只要 printf() 没有期望 float 的格式说明符,在期望 double 的说明符上 - 这是因为传递给的值用于格式化的 printf() 是变量参数列表的一部分(printf() 原型中的 ...)。没有关于这些参数的类型信息,因此正如您所提到的,编译器必须始终提升它们(来自 C99 6.5.2.2/6“函数调用”):

如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并且具有 float 类型的参数将提升为 double。这些称为默认参数促销。

和 C99 6.5.2.2/7“函数调用”

函数原型声明符中的省略符号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。

因此,实际上,不可能将 float 传递给 printf() - 它总是会被提升为 double。这就是浮点值的格式说明符需要 double 的原因。

另外,由于将应用于 short 的自动升级,我真的不确定用于格式化 shorth 说明符是否严格必要的(尽管如果您想获取写入放在 short 中的流的字符数,则必须与 n 说明符一起使用)。它可能是用 C 语言编写的,因为它需要支持 n 说明符、历史原因或我没有想到的东西。

A lot of questions in one question... Here are answers to a couple:

This characteristic of character constants makes it possible to define a character constant such as 'FATE' , with four separate 8-bit ASCII codes stored in a 32-bit unit.However , attempting to assign such a character constant to a char variable results in only the last 8 bits being used , so the variable gets the value 'E'.

This is actually implementation defined behavior. So yes, there's a mistake in the book. Many books on C are written with the assumption that the only C compiler in the world is the one the author used when testing the examples.

The compiler the author use treated the characters in 'FATE' as the bytes of an integer with the 'F' being the most significant byte and 'E' being the least significant. Your compiler treats the characters in the literal as bytes of an inteder with 'F' being the least significant byte and 'E' the most significant. For example, The first method is how MSVC treats the value, while MinGW (a GCC compiler targeting Windows) treats the literal in the second way.

As far as there being no format specifier to printf() that expects float, on specifiers that expect double - this is because the values passed to printf() for formatting are part of the variable argument list (the ... in printf()'s prototype). There is not type information about these arguments, so as you mentioned, the compiler must always promote them (from C99 6.5.2.2/6 "Function calls"):

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.

And C99 6.5.2.2/7 "Function calls"

The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

So in effect, it's impossible to pass a float to printf() - it will always be promoted to a double. That's why the format specifiers for floating point values expect a double.

Also due to the automatic promotion that would be applied to short, I'm honestly not sure if the h specifier for formatting a short is strictly necessary (though it is necessary for use with the n specifier if you want to get the count of characters written to the stream placed in a short). It might be in C because it needs to be there to support the n specifier, historical reasons, or something that I'm just not thinking of.

亚希 2024-11-14 12:12:56

首先,char根据定义正好是 1 个字节宽。然后标准或多或少规定大小应该是:

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)

确切的大小因系统和编译器而异(char 除外),但在 32 位 Windows 上,GCC 和 VC 的大小为(AFAIK):

sizeof(short) == 2 (byte)
sizeof(int) == sizeof(long) == 4 (byte)

在这种情况下,您对“F”与“E”的观察是一个典型的字节序问题(小字节序与大字节序,“单词”如何存储在内存中)。

现在你的价值会发生什么变化?您有一个 8 位宽的变量。您分配了一个更大的值('FATE'356),但编译器知道它只允许存储 8 位,因此它会切断所有其他位。

First, a char is by definition exactly 1 byte wide. Then the standard more or less says that the sizes should be:

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)

The exact sizes vary (except for char) by system and compiler but on a 32 bit Windows the sizes with GCC and VC are (AFAIK):

sizeof(short) == 2 (byte)
sizeof(int) == sizeof(long) == 4 (byte)

Your observation of 'F' versus 'E' in this case is a typical endianness issue (little vs. big endian, how a "word" is stored in memory).

Now what happens to your value ? You have a variable that is 8 bit wide. You assign a bigger value ('FATE' or 356), but the compiler knows it only is allowed to store 8 bits so it cuts off all the other bits.

执手闯天涯 2024-11-14 12:12:56

致A:
3.) 这是由于大端和小端 CPU 架构的字节顺序不同造成的。您可以在小端(即 x86)上获取第一个字节,在大端 CPU(即 PPC)上获取最后一个字节。实际上,当 int 到 char 的转换完成时,你总是得到最低的 8 位,但 int 中的字符以相反的顺序存储。

7.) char 只能保存 8 位,因此当您将 int 分配给 char 变量时,其他所有内容都会被截断,并且以后永远无法从 char 变量中恢复。

致乙:
3.) 有时您可能只想打印 int 变量的最低 16 位,而不管高半部分是什么。为了某些优化而将多个整数值打包在单个变量中的情况并不罕见。这对于整数类型效果很好,但对于不直接支持按位运算的浮点类型没有多大意义,这可能就是 printf 中没有单独的 float 类型说明符的原因。

To A:
3.) This is due to the different byte orderings of big and little endian CPU achitectures. You get the first byte on a little endian (i.e. x86) and the last byte on a big endian CPU (i.e. PPC). Actually you get always the lowest 8 bit when the conversion fom int to char is done but the characters in the int are stored in reversed order.

7.) a char can only hold 8 bits, so everything else gets truncated in the moment you assign the int to a char variable and can never be restored from the char variable later.

To B:
3.) You might sometimes want to print only the lowest 16 bits of a int variable regardless of what is in the higher half. It is not uncommon to pack multiple integer values in a single variable for certain optimizations. This works well for integer types but makes not much sense for floating point types which don't support bitwise operations directly, which might be the reason why there is no separate type specifier for float in printf.

漫雪独思 2024-11-14 12:12:56

char 的长度为 1 个字节。一个字节的位长度可以是8、16、32位长。在通用计算机中,字符的位长通常为 8 位。所以字符所能表示的最大数量取决于字符的位长。要检查字符的位长度,请检查 limits.h 头文件,它在此文件中定义为 CHAR_BIT

char x = 'FATE' 可能取决于机器/编译器解释 'FATE' 的字节顺序。所以这取决于系统/编译器。请有人确认/更正这一点。

如果您的系统有 8 位字节,那么当您执行 c = 360 时,只有 360 的二进制表示形式的低 8 位将存储在变量中,因为 char数据总是分配 1 个字节的存储空间。因此 %d 将打印 100,因为当您在变量中赋值时,高位丢失了,只剩下低 8 位。

char is 1 byte long. The bit length of a byte can be 8, 16, 32 bits long. In general purpose computers generally the bitlength of character is 8 bits long. So the maximum number which the character can represent depends on the bitlength of the character. To check the bitlength of character check limits.h header file it is defined as CHAR_BIT in this file.

char x = 'FATE' will depend probably on the byte ordering which the machine/compiler will interpret the 'FATE' . So this depends on the system/compiler. Someone please confirm/correct this.

If your system has 8 bits byte, then, when you do c = 360 only the lower 8 bits of the binary representation of 360 will be stored in the variable, because char data is always allocated 1 byte of storage. So %d will print 100 because the upper bits were lost when you assigned the value in the variable, and what is left is only the lower 8 bits.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文