更好地理解c

时间:2017-06-07 19:19:45

标签: c floating-point int printf c99

当在c中调用变量参数函数时,整数参数被提升为int,浮点参数被提升为double

  

由于原型未指定可选参数的类型,因此在对可变参数函数的调用中,对可选参数值执行默认参数提升。这意味着charshort int类型的对象(无论是否已签名)会酌情提升为intunsigned int;并且float类型的对象被提升为double类型。因此,如果调用者将char作为可选参数传递,则会将其提升为int,并且该函数可以使用va_arg (ap, int)访问它。

int类型应该是32位机器上的4字节和64位机器上的8字节,是吗? 所以我想知道当我将long long int传递给类似printf的变量参数函数%lld格式时附加的内容。
而且,我再次想知道当我将long double变量传递给带有%Lf格式的printf时(无论是在32位还是64位机器上),会附加什么。

[被修改

在32位机器上,我试过这个:

#include <stdio.h>

int main(void)
{
    printf("sizeof(int) %d\n", sizeof(int));
    printf("sizeof(long int) %d\n", sizeof(long int));
    printf("sizeof(long long int) %d\n", sizeof(long long int));
    printf("%lld\n", 1LL<<33);

    printf("sizeof(float) %d\n", sizeof(float));
    printf("sizeof(double) %d\n", sizeof(double));
    printf("sizeof(long double) %d\n", sizeof(long double));
    return 0;
}

结果是:

sizeof(int) 4
sizeof(long int) 4
sizeof(long long int) 8
8589934592
sizeof(float) 4
sizeof(double) 8
sizeof(long double) 12

这让我觉得并非所有参数都被提升为int,否则我会打印0而不是8589934592。

也许只有小于int的参数才会提升为int。类似的东西可能适用于浮点类型。

[被修改

在64位机器上运行:

int main(void)
{
    printf("sizeof(int) %lu\n", sizeof(int));
    printf("sizeof(long) %lu\n", sizeof(long));
    printf("sizeof(long long) %lu\n", sizeof(long long));
    return 0;
}

并获取

sizeof(int) 4
sizeof(long) 8
sizeof(long long) 8

如果我完全理解标准,则只有charshort被提升为int。我想知道在较小的架构中会发生什么,例如16位或8位MCU。我认为int大小取决于体系结构,但我想知道{8}架构上sizeof(int)是否可以是1。在这种情况下,除非丢失一些内容,否则无法将short升级为int

3 个答案:

答案 0 :(得分:9)

&#34; int类型应该是32位机器上的4字节和64位机器上的8字节,是吗?&#34;不是。根据标准,ints must be at least 16 bits in width (§5.2.4.2.1),但没有进一步的规定。

当您将long long int传递给printf()时,不受the integer promotions (§6.3.1.1 2)的限制:

  

无论是int还是unsigned,都可以在表达式中使用以下内容   可以使用int:

     
      
  • 具有整数类型(int或unsigned int除外)的对象或表达式,其整数转换等级小于或等于   int和unsigned int的等级。
  •   
  • _Bool,int,signed int或unsigned int类型的位字段。
  •   
     

如果int可以表示原始类型的所有值(限制为   通过宽度,对于位字段),该值被转换为int;   否则,它将转换为unsigned int。这些被称为   整数提升.58)所有其他类型的整数不变   促销

如果您将long double传递给printf() no conversion is made (§6.5.2.2 6)

  

如果表示被调用函数的表达式具有类型   不包括原型,执行整数促销   每个参数和类型为float的参数都被提升为   双。这些被称为默认参数促销。

printf()语句中的参数对应的转换说明符与这些促销和转换无关,除非在说明符及其对应参数的类型不匹配的情况下存在未定义的行为。 / p>

因此,执行整数提升,float转换为double,但"No other conversions are performed implicitly" (§6.5.2.2 8)

解决您对问题的修改:&#34;这让我觉得并非所有参数都提升为int。&#34;正确。只有整数转换的整数类型排名&#34;小于或等于intunsigned int&#34的排名;受整数提升。浮点类型更简单; float被提升为double。就是这样。

值得指出的是,根据§6.2.5 10,有三种实际浮点类型floatdoublelong doublefloat可能持有的值是double可能持有的值的子集,而long double又是long double可能持有的值的子集。 }。因此,long long int类型无法晋升。

此外,根据§6.3.1.1 1

  

long long int的等级应大于long int的等级,   它应大于int的等级,它应该更大   比短的int的等级,它应该大于等级   签名char。

因此,long intint不可能被提升为unsigned intshort

至于你最后的担心,在某些实现中,int升级到int可能不会丢失一些比特,但请注意§6.2.5 8保证short }}必须能够包含int,因为short的转化排名必须大于volatile int flag1; ... 的转化排名:

  

对于具有相同签名和不同的任何两个整数类型   整数转换等级(见6.3.1.1),类型的值范围   具有较小整数转换等级是值的子范围   另一种。

答案 1 :(得分:3)

  

int类型应该是32位机器上的4字节和64位机器上的8字节,是吗?

可能不是。首先,C不保证int的大小,除了声明它必须至少2个字节(能够至少保持值2 ^ 16/2 - 1 = 32767)。 C中没有任何内容可以防止int为8个字节,但这不太方便。

惯例是:所有8位和16位计算机都使用16位int。所有其他计算机使用32位int。这是行业事实上的标准。任何与这种惯例的偏差都是非常奇特的,尽管理论上允许C。

  

所以我想知道当我将long long int传递给类似printf with%lld格式的变量参数函数时会追加什么。

你得到一个很长的int。没有促销,因为变量不是上述小类型之一。使用的格式说明符与促销规则无关。

  

这让我觉得并非所有参数都被提升为int

事实上。仅提升标准提及的类型。可以在C11 6.5.2.2/6中找到默认参数促销的正式定义:

  

...对每个参数执行整数提升,并且   具有float类型的参数被提升为double。这些是   称为默认参数促销。

意味着只提升小整数类型(参见整数提升规则)和float。没有其他类型。

为什么您认为打印各种类型尺寸的示例与默认参数促销有关,我不知道。

答案 2 :(得分:1)

  

所以我想知道当我将pipeline { agent any parameters { string(name: 'PARAM1', description: 'Param 1?') string(name: 'PARAM2', description: 'Param 2?') } stages { stage('Example') { steps { echo "${params}" script { def myparams = currentBuild.rawBuild.getAction(ParametersAction).getParameters() build job: 'downstream-pipeline-with-params', parameters: myparams } } } } } 传递给变量时会追加什么   参数函数类似于带有long long int格式的printf。而且,我想知道   将%lld变量传递给带有long double的printf时附加的内容   格式(无论是在32位还是64位机器上)。

没有任何事情发生,因为%Lf必须至少与long long int大小相同。即使在最多的&#34; pesimistic&#34;场景,其中int,参数仍然传递&#34;原样是&#34; (没有任何促销)。这同样适用于sizeof(long long int) == sizeof(int)