From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id BEABE1A1DF5 for ; Tue, 27 Sep 2016 07:30:07 -0700 (PDT) Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 52B83C04B94A; Tue, 27 Sep 2016 14:30:07 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-5.phx2.redhat.com [10.3.116.5]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u8REU5iq021033; Tue, 27 Sep 2016 10:30:06 -0400 To: "Cohen, Eugene" References: <0de4dd03-faa7-1608-9625-369ab5d6e682@redhat.com> Cc: "edk2-devel@lists.01.org" , "Kinney, Michael D" , Alexei Fedorov From: Laszlo Ersek Message-ID: Date: Tue, 27 Sep 2016 16:30:04 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 27 Sep 2016 14:30:07 +0000 (UTC) Subject: Re: What is the right way to print a UINTN? X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Sep 2016 14:30:08 -0000 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit On 09/27/16 14:29, Cohen, Eugene wrote: > Laszlo, > >> I print INTN / UINTN values with: >> - casting them unconditionally to INT64 / UINT64, >> - printing the converted values with the matching conversion >> specifiers, >> such as %Ld (for INT64) and %Lu or %Lx (for UINT64). >> >> This solution requires a bit more typing, and it is a bit pessimistic >> for 32-bit builds. On the positive side, it is robust / portable, and >> completely valid C. >> >> It is inspired by the standard C types intmax_t / uintmax_t. If you >> write portable C code and want to print a value of some integer type, >> where the spec only states "signed" or "unsigned integer type", but >> the >> actual type is either implementation defined or unspecified, >> converting >> the value to intmax_t / uintmax_t, and then printing it with %jd vs. %ju >> / %jx, is safe. > > Thanks - this makes sense. If this methodology is consistent with > standard C then perhaps it's the best compromise even if it's messy > to read. > > From a consistency perspective I see a lot of variation in usage - > often UINTNs are printed with %x / %d (technically it should be %u > but this is a common error - just compare the number of occurrences > of %u in MdeModulePkg versus %d). Printing UINTN with %x *or* with %d are equally bugs. For X64 / AARCH64 / IA64 builds, they are actual bugs (that happen to work most of the time). For Ia32 / ARM builds, %x is not an actual bug, just a portability one / code smell. And %d may or may not be an actual bug, dependent on the value being printed. > This means that the caller is > expecting that the value will never exceed 2^32-1 on 64-bit systems > since we are doing 64-bit to 32-bit truncation through the cast in > the VA_ARG macro. I think that the specifics why printing UINTN with %x (or %d) happens to work on X64 / AARCH64, for a subset of the UINTN values, are not interesting. As far as I'm concerned, even the argument *sizes* are wrong, which might as well lead to incorrect accesses to the stack. > I'm concerned that this requires the developer to > know the constraints on the value in all circumstances which seems > dubious - after all that's why we have types in the first place, so > the tools can help us do the right thing. The developer is first and foremost required to match the conversion specifiers to the types of the arguments being passed. For UINTN there is no dedicated conversion specifier, hence my recommendation for the casting. > I'm envisioning having to create a slide in the future for UEFI > training about the proper use of UINTNs and describing "If you think > it may exceed 2^32-1 then upcast to UINT64, otherwise don't worry > about it" and it makes me squirm. It makes me squirm too. I think the slide should recommend the casting that I proposed. ;) "There is no conversion specifier dedicated to UINTN; the portable way to print it is to cast it to UINT64, then print it with %Lx." Thanks Laszlo