0

This isn't quite answered by static const vs #define or #defining constants in C++.

In when I did a lot of programming in C, ANSI C was brand new. We mostly used #define to define constants. I've been made aware that this is no longer a best practice (https://codereview.stackexchange.com/questions/123848/verifying-e-mail-address-in-c/123856#123856).

Using #define I can use previous constants to define the current constant, an exampe is

#define EMAIL_CHAR_ARRAY_SIZE 40
#define GOOD_EMAIL_ADDRESS  1
#define BAD_EMAIL_ADDRESS 0
#define MIMIMUM_USER_NAME_LENGTH 1
#define AT_SIGN_LENGTH 1
#define DOT_LENGTH 1
#define MINIMUM_DOMAIN_LENGTH 1
#define MINIMUM_ROOT_DOMAIN_LENGTH 2
#define MINIUMUM_EMAIL_LENGTH MIMIMUM_USER_NAME_LENGTH + AT_SIGN_LENGTH + MINIMUM_DOMAIN_LENGTH + MINIMUM_ROOT_DOMAIN_LENGTH

I have a program (below) where I have attempted to use static const rather than #define, however the constant MINIUMUM_EMAIL_LENGTH doesn't compile when I try to use static const using the previous constants. Is there a way to use previously defined constants in a static const TYPE declaration?

const_testemail.c:12:5: error: initializer element is not constant
     static const int MINIUMUM_EMAIL_LENGTH = (MIMIMUM_USER_NAME_LENGTH + AT_SIGN_LENGTH + MINIMUM_DOMAIN_LENGTH + MINIMUM_ROOT_DOMAIN_LENGTH);


#include <stdio.h>
#include <string.h>

static const int EMAIL_CHAR_ARRAY_SIZE = 40;
static const int GOOD_EMAIL_ADDRESS  = 1;
static const int BAD_EMAIL_ADDRESS = 0;
static const int MIMIMUM_USER_NAME_LENGTH = 1;
static const int AT_SIGN_LENGTH = 1;
static const int DOT_LENGTH = 1;
static const int MINIMUM_DOMAIN_LENGTH = 1;
static const int MINIMUM_ROOT_DOMAIN_LENGTH = 2;
/*  Doesn't compile 
 *  static const int MINIUMUM_EMAIL_LENGTH = MIMIMUM_USER_NAME_LENGTH + AT_SIGN_LENGTH + MINIMUM_DOMAIN_LENGTH + MINIMUM_ROOT_DOMAIN_LENGTH;
 *  */

#define MINIUMUM_EMAIL_LENGTH (MIMIMUM_USER_NAME_LENGTH + AT_SIGN_LENGTH + MINIMUM_DOMAIN_LENGTH + MINIMUM_ROOT_DOMAIN_LENGTH)

int isEmailAddressProper(const char EmailAddress[EMAIL_CHAR_ARRAY_SIZE])
{
    int     EmailAddressIsGood = GOOD_EMAIL_ADDRESS;
    int     LengthOfEmailAddress;
    char    *AtSignLocation, *pos2;
    int     rootDomainLength;

    LengthOfEmailAddress = strlen(EmailAddress);
    if (LengthOfEmailAddress < MINIUMUM_EMAIL_LENGTH)
    {
        printf("The length of the email address is less than the minimum lenght %d\n", MINIUMUM_EMAIL_LENGTH);
        EmailAddressIsGood = BAD_EMAIL_ADDRESS;
    }

    AtSignLocation = strchr(EmailAddress, '@'); /* get the first instance of @ */
    if (!AtSignLocation)
    {
        printf("There is no @ in the email address\n");
        EmailAddressIsGood = BAD_EMAIL_ADDRESS;
        return EmailAddressIsGood;
    }

    if (AtSignLocation == EmailAddress) { /* Is @ the first character? */
        printf("There is no user name in the email address, @ is the first character\n");
        EmailAddressIsGood = BAD_EMAIL_ADDRESS;
    }

    pos2 = strrchr(EmailAddress, '@'); /* find any other @ */
    if ((pos2) && (AtSignLocation != pos2)) {
        printf("There is more than 1 @ in the email address\n");
        EmailAddressIsGood = BAD_EMAIL_ADDRESS;
    }

    pos2 = strrchr(EmailAddress, '.'); /* get the last instance of '.' */
    if (AtSignLocation > pos2) /* is . before @ ? */
    {            printf("There is no root domain in the email address\n");
        EmailAddressIsGood = BAD_EMAIL_ADDRESS;
    }

    pos2++;
    rootDomainLength = LengthOfEmailAddress - ((int)(pos2 - EmailAddress));
    /* if root domain less than length 2 */
    if (rootDomainLength < MINIMUM_ROOT_DOMAIN_LENGTH)
    {
        printf("The root domain length (%d) is less than the minimum length required (%d) in the email address\n", rootDomainLength, MINIMUM_ROOT_DOMAIN_LENGTH);
        EmailAddressIsGood = BAD_EMAIL_ADDRESS;
    }

    return EmailAddressIsGood;
}

void GetAndValidateEmailAddress(char EmailAddress[EMAIL_CHAR_ARRAY_SIZE])
{
    int EmailAddressIsGood = BAD_EMAIL_ADDRESS;
    char TempEmail[EMAIL_CHAR_ARRAY_SIZE];

    while (!EmailAddressIsGood)
    {
        scanf("%39s", TempEmail);
        EmailAddressIsGood = isEmailAddressProper(TempEmail);
        if (!EmailAddressIsGood) {
            printf("The email address is not in the proper format, please re-enter the email address\n");
        }
    }

   strcpy(EmailAddress, TempEmail);
}

main()
{
    char EmailAddress[EMAIL_CHAR_ARRAY_SIZE];

    printf("Please enter the email address\n");
    GetAndValidateEmailAddress(EmailAddress);
    printf("The email address you entered is %s\n", EmailAddress);
}
Community
  • 1
  • 1
pacmaninbw
  • 439
  • 1
  • 10
  • 22
  • @Olaf What your answer states to me is that there is no way to create constants using C language. This would be a very bad programming practice. – pacmaninbw Mar 26 '16 at 16:45
  • No, I did not state this. Because that's what macros are used for. Note that C very well has constants! `1` is a constant of type `int`, `0.3f` is a `float` constant, etc. The problem you have are **symbolic** constants with a user-defined type. Use macros for them. Different translation phase, but that's how it works in C. If you are in rome behave like a roman. – too honest for this site Mar 26 '16 at 16:47
  • Not sure how your compiler works, but you have a typo in your commented macro. Fix that and try again. Are you are this is purely C? – Gerhard Stein Mar 26 '16 at 16:52
  • #define s are assigned in **pre**processing, while const and enum are assigned during compilation, so you can have **enum {fixed=42}; static const fixed_n = fixed;**. – Arif Burhan Mar 26 '16 at 16:53
  • @ArifBurhan: You missed something. It is also quite useless and overly complicated. Also, _enum-constants_ are `int` only. In C using macros with proper names is the way to go. – too honest for this site Mar 26 '16 at 16:56
  • @ Gerstrong If there Is a typo, it is a copy and paste error, the program compiles using gcc on Centos 7. I will look into correcting this. @Olaf I originally used #define in the answer to a question on CodeReview. I was down voted for the use of #define, that led me to ask this question. I would never use #define in C++ for constants, but up until now I would always use #define for constants in C. I always make a distinction between C and C++, some others no longer make that distinction as far as I can tell. – pacmaninbw Mar 26 '16 at 17:14
  • @pacmaninbw: Is there a reason you ignore my answer? Please comment the answer at the answer. Also, if it helped, please upvote/accept. Downvoting for using macros in C is nonsense, but there are always - strange - people around. Possibly someone who thinks C++ is C with classes. I don't know the exact circumstances of that DV, so this is just a general statement. Using macros is fine and the names you use are ok. – too honest for this site Mar 26 '16 at 17:19

1 Answers1

0

C does not have symbolic constants other than enum-constants (which are always of type int). #define is a macro and part of the preprocessor. It is a textual replacement before the actual C language compilation.

const qualified variables are semantically still variables. The qualifier is a guarantee by the programmer he will not change the value. The compiler may rely on this guarantee. Breaking the contract invokes undefined behaviour, but it is not necessarily enforced by the run-time environment.

Static initialisers and array indexes at the file-level require a constant expression, thus the error. Briefly, a constant expression must yield a constant value at compile-time, thus you cannot use variables.

Note the array parameter in your function has a similar problem. But here you can use a variable length array. However, you either can use an empty length ([]) or pass the length as a preceeding parameter explicitly; global variables don't work:

int isEmailAddressProper(size_t len, const char EmailAddress[len])

C++ is a different language with similar syntax/grammar, and quite some different semantics even for the same grammar. You often cannot apply knowledge from on language to the other.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • Ok, since static const int is still a variable, it can't be used in in defining a constant, this is what you are saying. I've added the error message, there are no warnings. – pacmaninbw Mar 26 '16 at 17:26