关于 C 参数提升的问题
好吧,实际上我已经研究了如何使用循环来使我的代码更高效,以便我可以使用应该重复的特定代码块,而无需一遍又一遍地输入它,并且在尝试使用我学到的东西之后距离编程还远了,我觉得是时候进入下一章学习如何使用控制语句来指导程序做出决定了。
但问题是,在我继续之前,我仍然有一些问题需要任何专家对之前的内容的帮助。实际上这是关于数据类型的。
A.字符类型
- 我从《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'
。
所以读完这篇文章后我做的下一件事当然是按照它提到的内容进行操作,即我尝试将单词
FATE
存储在具有chargrade
的变量上,并且尝试编译并查看使用printf()
存储的内容,但我得到的是',而不是打印出字符
.'E'
F'这是否意味着书中存在一些错误?还是我误解了什么?
从上面的句子中,有一行说C将字符常量视为
int
类型。因此,为了尝试一下,我为char
类型分配了一个大于255
(例如356
)的数字。由于
356
在 32 位int
的范围内(我运行的是 Windows 7),因此我希望它会打印出356 当我使用
%d
说明符时。但它没有打印
356
,而是给我100
,这是最后 8 位值。为什么会发生这种情况?我认为
char == int == 32位
? (尽管它之前确实提到 char 只是一个字节)。
B. Int 和 Floating 类型
我明白,当以
short
类型存储在变量中的数字传递给可变参数函数或任何隐式原型函数时,它将自动提升为int
类型。浮点类型也会出现这种情况,当传递
float
类型的浮点数时,它会被转换为double
类型,这就是为什么有float
类型没有说明符,但只有%f
表示double
,%Lf
表示long double
。但是为什么有一个
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
- I extract the following from the book C primer Plus 5th ed:
Somewhat oddly , C treats character
constans as typeint
rather thanchar
. For example, on an ASCII system
with a 32-bitint
and an 8-bitchar
, 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 achar
variable results
in only the last 8 bits being used,
so the variable gets the value'E'
.
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 withchar grade
and try to compile and see what it'll be stored usingprintf()
, but instead of getting the character'E'
printed out, what I get is'F'
.Does this mean there's some mistake in the book? OR is there something I misunderstood?
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 than255
, (e.x.356
) to thechar
type.Since
356
is within the range of 32-bitint
(I'm running Windows 7), therefore I expect it would print out356
when I use the%d
specifier.But instead of printing
356
, it gives me100
, which is the last 8-bits value.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
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 toint
type.This also happen to floating point type, when a floating-point number with
float
type is passed, it'll be converted todouble
type, that is why there's no specifier for thefloat
type but instead there's only%f
fordouble
and%Lf
forlong double
.But why there's a specifier for
short
type although it is also promoted but notfloat
type? Why don't they just give a specifier forfloat
type with a modifier like%hf
or something? Is there anything logical or technical behind this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一个问题中有很多问题......以下是几个问题的答案:
这实际上是实现定义的行为。所以,是的,书中有一个错误。许多关于 C 的书籍在编写时都假设世界上唯一的 C 编译器是作者在测试示例时使用的编译器。
作者使用的编译器将“FATE”中的字符视为整数的字节,其中“F”是最高有效字节,“E”是最低有效字节。您的编译器将文字中的字符视为整数字节,其中“F”是最低有效字节,“E”是最高有效字节。例如,第一种方法是 MSVC 如何处理值,而 MinGW(面向 Windows 的 GCC 编译器)则以第二种方式处理文字。
只要
printf()
没有期望float
的格式说明符,在期望double
的说明符上 - 这是因为传递给的值用于格式化的printf()
是变量参数列表的一部分(printf()
原型中的...
)。没有关于这些参数的类型信息,因此正如您所提到的,编译器必须始终提升它们(来自 C99 6.5.2.2/6“函数调用”):和 C99 6.5.2.2/7“函数调用”
因此,实际上,不可能将
float
传递给printf()
- 它总是会被提升为double
。这就是浮点值的格式说明符需要double
的原因。另外,由于将应用于
short
的自动升级,我真的不确定用于格式化short
的h
说明符是否严格必要的(尽管如果您想获取写入放在short
中的流的字符数,则必须与n
说明符一起使用)。它可能是用 C 语言编写的,因为它需要支持n
说明符、历史原因或我没有想到的东西。A lot of questions in one question... Here are answers to a couple:
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 expectsfloat
, on specifiers that expectdouble
- this is because the values passed toprintf()
for formatting are part of the variable argument list (the...
inprintf()
'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"):And C99 6.5.2.2/7 "Function calls"
So in effect, it's impossible to pass a
float
toprintf()
- it will always be promoted to adouble
. That's why the format specifiers for floating point values expect adouble
.Also due to the automatic promotion that would be applied to
short
, I'm honestly not sure if theh
specifier for formatting ashort
is strictly necessary (though it is necessary for use with then
specifier if you want to get the count of characters written to the stream placed in ashort
). It might be in C because it needs to be there to support then
specifier, historical reasons, or something that I'm just not thinking of.首先,
char
根据定义正好是 1 个字节宽。然后标准或多或少规定大小应该是:确切的大小因系统和编译器而异(
char
除外),但在 32 位 Windows 上,GCC 和 VC 的大小为(AFAIK):在这种情况下,您对“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: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):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'
or356
), but the compiler knows it only is allowed to store 8 bits so it cuts off all the other bits.致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.
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 checklimits.h
header file it is defined asCHAR_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, becausechar
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.